summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk16
-rw-r--r--api/current.xml3650
-rw-r--r--camera/libcameraservice/Android.mk1
-rw-r--r--camera/libcameraservice/CameraHardwareStub.h4
-rw-r--r--camera/libcameraservice/CameraService.cpp14
-rw-r--r--cmds/app_process/app_main.cpp4
-rw-r--r--cmds/bootanimation/BootAnimation.cpp2
-rw-r--r--cmds/bootanimation/bootanimation_main.cpp6
-rw-r--r--cmds/dumpsys/Android.mk4
-rw-r--r--cmds/dumpsys/dumpsys.cpp6
-rw-r--r--cmds/runtime/Android.mk1
-rw-r--r--cmds/runtime/ServiceManager.cpp4
-rw-r--r--cmds/runtime/ServiceManager.h2
-rw-r--r--cmds/runtime/main_runtime.cpp8
-rw-r--r--cmds/service/Android.mk3
-rw-r--r--cmds/service/service.cpp6
-rw-r--r--cmds/surfaceflinger/Android.mk1
-rw-r--r--cmds/surfaceflinger/main_surfaceflinger.cpp6
-rw-r--r--cmds/system_server/Android.mk1
-rw-r--r--cmds/system_server/library/Android.mk1
-rw-r--r--cmds/system_server/library/system_init.cpp6
-rw-r--r--cmds/system_server/system_main.cpp2
-rw-r--r--core/java/android/accounts/AbstractAccountAuthenticator.java196
-rw-r--r--core/java/android/accounts/Account.aidl (renamed from include/utils/executablepath.h)15
-rw-r--r--core/java/android/accounts/Account.java84
-rw-r--r--core/java/android/accounts/AccountAuthenticatorActivity.java102
-rw-r--r--core/java/android/accounts/AccountAuthenticatorCache.java73
-rw-r--r--core/java/android/accounts/AccountAuthenticatorResponse.java82
-rw-r--r--core/java/android/accounts/AccountManager.java1073
-rw-r--r--core/java/android/accounts/AccountManagerResponse.java74
-rw-r--r--core/java/android/accounts/AccountManagerService.java1185
-rw-r--r--core/java/android/accounts/AccountMonitor.java174
-rw-r--r--core/java/android/accounts/AccountsServiceConstants.java78
-rw-r--r--core/java/android/accounts/AuthenticatorBindHelper.java251
-rw-r--r--core/java/android/accounts/AuthenticatorException.java (renamed from include/utils.h)33
-rw-r--r--core/java/android/accounts/ChooseAccountActivity.java78
-rw-r--r--core/java/android/accounts/Constants.java50
-rw-r--r--core/java/android/accounts/Future1.java46
-rw-r--r--core/java/android/accounts/Future1Callback.java (renamed from libs/utils/executablepath_linux.cpp)18
-rw-r--r--core/java/android/accounts/Future2.java57
-rw-r--r--core/java/android/accounts/Future2Callback.java20
-rw-r--r--core/java/android/accounts/IAccountAuthenticator.aidl68
-rw-r--r--core/java/android/accounts/IAccountAuthenticatorResponse.aidl27
-rw-r--r--core/java/android/accounts/IAccountManager.aidl62
-rw-r--r--core/java/android/accounts/IAccountManagerResponse.aidl27
-rw-r--r--core/java/android/accounts/IAccountsService.aidl54
-rw-r--r--core/java/android/accounts/NetworkErrorException.java31
-rw-r--r--core/java/android/accounts/OnAccountsUpdatedListener.java (renamed from core/java/android/accounts/AccountMonitorListener.java)6
-rw-r--r--core/java/android/accounts/OperationCanceledException.java31
-rwxr-xr-xcore/java/android/accounts/package.html5
-rw-r--r--core/java/android/app/ApplicationContext.java16
-rw-r--r--core/java/android/bluetooth/BluetoothInputStream.java98
-rw-r--r--core/java/android/bluetooth/BluetoothOutputStream.java87
-rw-r--r--core/java/android/bluetooth/BluetoothServerSocket.java150
-rw-r--r--core/java/android/bluetooth/BluetoothSocket.java197
-rw-r--r--core/java/android/bluetooth/Database.java200
-rw-r--r--core/java/android/bluetooth/RfcommSocket.java674
-rw-r--r--core/java/android/content/AbstractCursorEntityIterator.java112
-rw-r--r--core/java/android/content/AbstractSyncableContentProvider.java385
-rw-r--r--core/java/android/content/AbstractTableMerger.java610
-rw-r--r--core/java/android/content/ActiveSyncInfo.java9
-rw-r--r--core/java/android/content/ContentProvider.java92
-rw-r--r--core/java/android/content/ContentProviderClient.java135
-rw-r--r--core/java/android/content/ContentProviderNative.java207
-rw-r--r--core/java/android/content/ContentProviderOperation.java523
-rw-r--r--core/java/android/content/ContentProviderResult.java84
-rw-r--r--core/java/android/content/ContentResolver.java155
-rw-r--r--core/java/android/content/ContentService.java5
-rw-r--r--core/java/android/content/Context.java10
-rw-r--r--core/java/android/content/Entity.aidl20
-rw-r--r--core/java/android/content/Entity.java104
-rw-r--r--core/java/android/content/EntityIterator.java49
-rw-r--r--core/java/android/content/IContentProvider.java14
-rw-r--r--core/java/android/content/IContentService.aidl5
-rw-r--r--core/java/android/content/IEntityIterator.java181
-rw-r--r--core/java/android/content/ISyncAdapter.aidl3
-rw-r--r--core/java/android/content/Intent.java27
-rw-r--r--core/java/android/content/IntentFilter.java1
-rw-r--r--core/java/android/content/OperationApplicationException.java36
-rw-r--r--core/java/android/content/SyncAdapter.java9
-rw-r--r--core/java/android/content/SyncAdapterNew.java135
-rw-r--r--core/java/android/content/SyncAdapterType.java57
-rw-r--r--core/java/android/content/SyncAdaptersCache.java77
-rw-r--r--core/java/android/content/SyncManager.java418
-rw-r--r--core/java/android/content/SyncStateContentProviderHelper.java43
-rw-r--r--core/java/android/content/SyncStorageEngine.java62
-rw-r--r--core/java/android/content/SyncableContentProvider.java29
-rw-r--r--core/java/android/content/TempProviderSyncAdapter.java15
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl1
-rw-r--r--core/java/android/content/pm/PackageManager.java2
-rw-r--r--core/java/android/content/pm/ProviderInfo.java6
-rw-r--r--core/java/android/content/pm/RegisteredServicesCache.java233
-rw-r--r--core/java/android/database/AbstractWindowedCursor.java42
-rw-r--r--core/java/android/database/CursorWindow.java51
-rw-r--r--core/java/android/database/DatabaseUtils.java47
-rw-r--r--core/java/android/database/sqlite/SQLiteQueryBuilder.java15
-rw-r--r--core/java/android/net/WebAddress.java2
-rw-r--r--core/java/android/net/http/Request.java9
-rw-r--r--core/java/android/net/http/RequestQueue.java73
-rw-r--r--core/java/android/os/Debug.java19
-rw-r--r--core/java/android/os/Exec.java63
-rw-r--r--core/java/android/os/LatencyTimer.java94
-rw-r--r--core/java/android/os/RemoteCallbackList.java57
-rw-r--r--core/java/android/preference/RingtonePreference.java5
-rw-r--r--core/java/android/preference/VolumePreference.java15
-rw-r--r--core/java/android/provider/Calendar.java10
-rw-r--r--core/java/android/provider/Contacts.java27
-rw-r--r--core/java/android/provider/ContactsContract.java805
-rw-r--r--core/java/android/provider/Downloads.java46
-rw-r--r--core/java/android/provider/Im.java259
-rw-r--r--core/java/android/provider/Settings.java42
-rw-r--r--core/java/android/provider/SocialContract.java174
-rw-r--r--core/java/android/provider/SubscribedFeeds.java31
-rw-r--r--core/java/android/provider/Sync.java649
-rw-r--r--core/java/android/provider/SyncConstValue.java11
-rw-r--r--core/java/android/provider/Telephony.java14
-rw-r--r--core/java/android/syncml/pim/vcard/ContactStruct.java27
-rw-r--r--core/java/android/view/MotionEvent.java73
-rw-r--r--core/java/android/view/SurfaceView.java3
-rw-r--r--core/java/android/view/ViewRoot.java29
-rw-r--r--core/java/android/view/ViewStub.java18
-rw-r--r--core/java/android/view/Window.java6
-rw-r--r--core/java/android/webkit/BrowserFrame.java23
-rw-r--r--core/java/android/webkit/CacheManager.java19
-rw-r--r--core/java/android/webkit/CallbackProxy.java138
-rw-r--r--core/java/android/webkit/CookieManager.java12
-rw-r--r--core/java/android/webkit/CookieSyncManager.java47
-rw-r--r--core/java/android/webkit/DataLoader.java29
-rw-r--r--core/java/android/webkit/DebugFlags.java48
-rw-r--r--core/java/android/webkit/FrameLoader.java8
-rw-r--r--core/java/android/webkit/HttpDateTime.java39
-rw-r--r--core/java/android/webkit/JWebCoreJavaBridge.java57
-rw-r--r--core/java/android/webkit/LoadListener.java101
-rw-r--r--core/java/android/webkit/MimeTypeMap.java1
-rw-r--r--core/java/android/webkit/Network.java14
-rw-r--r--core/java/android/webkit/PluginManager.java157
-rw-r--r--core/java/android/webkit/SslErrorHandler.java14
-rw-r--r--core/java/android/webkit/StreamLoader.java8
-rw-r--r--core/java/android/webkit/URLUtil.java2
-rw-r--r--core/java/android/webkit/WebBackForwardList.java2
-rw-r--r--core/java/android/webkit/WebChromeClient.java28
-rw-r--r--core/java/android/webkit/WebSettings.java177
-rw-r--r--core/java/android/webkit/WebStorage.java283
-rw-r--r--core/java/android/webkit/WebSyncManager.java10
-rw-r--r--core/java/android/webkit/WebTextView.java (renamed from core/java/android/webkit/TextDialog.java)183
-rw-r--r--core/java/android/webkit/WebView.java1357
-rw-r--r--core/java/android/webkit/WebViewCore.java398
-rw-r--r--core/java/android/widget/AbsSeekBar.java5
-rw-r--r--core/java/android/widget/AdapterView.java2
-rw-r--r--core/java/android/widget/ArrayAdapter.java7
-rw-r--r--core/java/android/widget/AutoCompleteTextView.java83
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java61
-rw-r--r--core/java/com/google/android/mms/pdu/EncodedStringValue.java12
-rw-r--r--core/jni/ActivityManager.cpp6
-rw-r--r--core/jni/Android.mk5
-rw-r--r--core/jni/AndroidRuntime.cpp127
-rw-r--r--core/jni/CursorWindow.cpp2
-rw-r--r--core/jni/CursorWindow.h2
-rw-r--r--core/jni/android/graphics/Bitmap.cpp2
-rw-r--r--core/jni/android/graphics/Path.cpp5
-rw-r--r--core/jni/android/graphics/Region.cpp2
-rw-r--r--core/jni/android_bluetooth_BluetoothSocket.cpp517
-rw-r--r--core/jni/android_bluetooth_Database.cpp183
-rw-r--r--core/jni/android_bluetooth_RfcommSocket.cpp621
-rw-r--r--core/jni/android_bluetooth_common.cpp5
-rw-r--r--core/jni/android_bluetooth_common.h2
-rw-r--r--core/jni/android_database_CursorWindow.cpp65
-rw-r--r--core/jni/android_database_SQLiteDatabase.cpp5
-rw-r--r--core/jni/android_hardware_Camera.cpp2
-rw-r--r--core/jni/android_media_AudioTrack.cpp4
-rw-r--r--core/jni/android_os_Exec.cpp215
-rw-r--r--core/jni/android_util_Binder.cpp10
-rw-r--r--core/jni/android_util_Binder.h2
-rw-r--r--core/jni/android_util_Process.cpp6
-rw-r--r--core/res/AndroidManifest.xml35
-rw-r--r--core/res/res/values/attrs.xml374
-rw-r--r--core/res/res/values/config.xml2
-rw-r--r--core/res/res/values/public.xml54
-rw-r--r--core/res/res/values/strings.xml55
-rw-r--r--docs/html/guide/developing/tools/ddms.jd13
-rw-r--r--include/android_runtime/AndroidRuntime.h3
-rw-r--r--include/binder/Binder.h (renamed from include/utils/Binder.h)5
-rw-r--r--include/binder/BpBinder.h (renamed from include/utils/BpBinder.h)6
-rw-r--r--include/binder/IBinder.h (renamed from include/utils/IBinder.h)6
-rw-r--r--include/binder/IInterface.h (renamed from include/utils/IInterface.h)26
-rw-r--r--include/binder/IMemory.h (renamed from include/utils/IMemory.h)10
-rw-r--r--include/binder/IPCThreadState.h (renamed from include/utils/IPCThreadState.h)4
-rw-r--r--include/binder/IPermissionController.h (renamed from include/utils/IPermissionController.h)2
-rw-r--r--include/binder/IServiceManager.h (renamed from include/utils/IServiceManager.h)4
-rw-r--r--include/binder/MemoryBase.h (renamed from include/utils/MemoryBase.h)2
-rw-r--r--include/binder/MemoryDealer.h (renamed from include/utils/MemoryDealer.h)13
-rw-r--r--include/binder/MemoryHeapBase.h (renamed from include/utils/MemoryHeapBase.h)2
-rw-r--r--include/binder/MemoryHeapPmem.h (renamed from include/utils/MemoryHeapPmem.h)6
-rw-r--r--include/binder/Parcel.h (renamed from include/utils/Parcel.h)5
-rw-r--r--include/binder/ProcessState.h (renamed from include/utils/ProcessState.h)2
-rw-r--r--include/media/AudioRecord.h4
-rw-r--r--include/media/AudioTrack.h4
-rw-r--r--include/media/IAudioFlinger.h2
-rw-r--r--include/media/IAudioFlingerClient.h2
-rw-r--r--include/media/IAudioRecord.h4
-rw-r--r--include/media/IAudioTrack.h4
-rw-r--r--include/media/IMediaMetadataRetriever.h6
-rw-r--r--include/media/IMediaPlayer.h4
-rw-r--r--include/media/IMediaPlayerClient.h4
-rw-r--r--include/media/IMediaPlayerService.h4
-rw-r--r--include/media/IMediaRecorder.h2
-rw-r--r--include/media/mediametadataretriever.h2
-rw-r--r--include/media/mediaplayer.h2
-rw-r--r--include/media/mediarecorder.h5
-rw-r--r--include/media/mediascanner.h5
-rw-r--r--include/private/binder/Static.h (renamed from libs/utils/executablepath_darwin.cpp)34
-rw-r--r--include/private/binder/binder_module.h (renamed from include/private/utils/binder_module.h)0
-rw-r--r--include/private/utils/Static.h23
-rw-r--r--include/ui/CameraHardwareInterface.h2
-rw-r--r--include/ui/EventHub.h5
-rw-r--r--include/ui/ICamera.h6
-rw-r--r--include/ui/ICameraClient.h6
-rw-r--r--include/ui/ICameraService.h4
-rw-r--r--include/ui/IOverlay.h2
-rw-r--r--include/ui/ISurface.h2
-rw-r--r--include/ui/ISurfaceComposer.h2
-rw-r--r--include/ui/ISurfaceFlingerClient.h2
-rw-r--r--include/ui/Overlay.h2
-rw-r--r--include/ui/Region.h2
-rw-r--r--include/utils/LogSocket.h20
-rw-r--r--include/utils/Pipe.h108
-rw-r--r--include/utils/Socket.h80
-rw-r--r--include/utils/StringArray.h83
-rw-r--r--include/utils/TextOutput.h4
-rw-r--r--include/utils/TimerProbe.h72
-rw-r--r--include/utils/Timers.h13
-rw-r--r--include/utils/inet_address.h103
-rw-r--r--include/utils/misc.h2
-rw-r--r--include/utils/ported.h50
-rw-r--r--include/utils/string_array.h135
-rw-r--r--include/utils/threads.h10
-rw-r--r--libs/audioflinger/Android.mk2
-rw-r--r--libs/audioflinger/AudioFlinger.cpp13
-rw-r--r--libs/audioflinger/AudioFlinger.h2
-rw-r--r--libs/binder/Android.mk44
-rw-r--r--libs/binder/Binder.cpp (renamed from libs/utils/Binder.cpp)25
-rw-r--r--libs/binder/BpBinder.cpp (renamed from libs/utils/BpBinder.cpp)37
-rw-r--r--libs/binder/IInterface.cpp (renamed from libs/utils/IInterface.cpp)9
-rw-r--r--libs/binder/IMemory.cpp (renamed from libs/utils/IMemory.cpp)28
-rw-r--r--libs/binder/IPCThreadState.cpp (renamed from libs/utils/IPCThreadState.cpp)10
-rw-r--r--libs/binder/IPermissionController.cpp (renamed from libs/utils/IPermissionController.cpp)12
-rw-r--r--libs/binder/IServiceManager.cpp (renamed from libs/utils/IServiceManager.cpp)14
-rw-r--r--libs/binder/MemoryBase.cpp (renamed from libs/utils/MemoryBase.cpp)2
-rw-r--r--libs/binder/MemoryDealer.cpp (renamed from libs/utils/MemoryDealer.cpp)20
-rw-r--r--libs/binder/MemoryHeapBase.cpp (renamed from libs/utils/MemoryHeapBase.cpp)2
-rw-r--r--libs/binder/MemoryHeapPmem.cpp (renamed from libs/utils/MemoryHeapPmem.cpp)6
-rw-r--r--libs/binder/Parcel.cpp (renamed from libs/utils/Parcel.cpp)17
-rw-r--r--libs/binder/ProcessState.cpp (renamed from libs/utils/ProcessState.cpp)12
-rw-r--r--libs/binder/Static.cpp53
-rw-r--r--libs/rs/Android.mk143
-rw-r--r--libs/rs/RenderScript.h186
-rw-r--r--libs/rs/RenderScriptEnv.h97
-rw-r--r--libs/rs/java/Android.mk1
-rw-r--r--libs/rs/java/Fountain/Android.mk31
-rw-r--r--libs/rs/java/Fountain/AndroidManifest.xml13
-rwxr-xr-xlibs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.pngbin0 -> 104862 bytes
-rw-r--r--libs/rs/java/Fountain/res/raw/fountain.c104
-rw-r--r--libs/rs/java/Fountain/src/com/android/fountain/Fountain.java87
-rw-r--r--libs/rs/java/Fountain/src/com/android/fountain/FountainView.java170
-rw-r--r--libs/rs/java/Fountain/src/com/android/fountain/RSSurfaceView.java154
-rw-r--r--libs/rs/java/Fountain/src/com/android/fountain/RenderScript.java818
-rw-r--r--libs/rs/jni/RenderScript_jni.cpp912
-rw-r--r--libs/rs/rs.spec406
-rw-r--r--libs/rs/rsAdapter.cpp245
-rw-r--r--libs/rs/rsAdapter.h96
-rw-r--r--libs/rs/rsAllocation.cpp478
-rw-r--r--libs/rs/rsAllocation.h96
-rw-r--r--libs/rs/rsComponent.cpp43
-rw-r--r--libs/rs/rsComponent.h75
-rw-r--r--libs/rs/rsContext.cpp313
-rw-r--r--libs/rs/rsContext.h123
-rw-r--r--libs/rs/rsDevice.cpp62
-rw-r--r--libs/rs/rsDevice.h50
-rw-r--r--libs/rs/rsElement.cpp434
-rw-r--r--libs/rs/rsElement.h98
-rw-r--r--libs/rs/rsLocklessFifo.cpp182
-rw-r--r--libs/rs/rsLocklessFifo.h74
-rw-r--r--libs/rs/rsMatrix.cpp139
-rw-r--r--libs/rs/rsMatrix.h84
-rw-r--r--libs/rs/rsObjectBase.cpp48
-rw-r--r--libs/rs/rsObjectBase.h90
-rw-r--r--libs/rs/rsProgram.cpp48
-rw-r--r--libs/rs/rsProgram.h59
-rw-r--r--libs/rs/rsProgramFragment.cpp219
-rw-r--r--libs/rs/rsProgramFragment.h98
-rw-r--r--libs/rs/rsProgramFragmentStore.cpp252
-rw-r--r--libs/rs/rsProgramFragmentStore.h89
-rw-r--r--libs/rs/rsProgramVertex.cpp133
-rw-r--r--libs/rs/rsProgramVertex.h76
-rw-r--r--libs/rs/rsSampler.cpp160
-rw-r--r--libs/rs/rsSampler.h92
-rw-r--r--libs/rs/rsScript.cpp54
-rw-r--r--libs/rs/rsScript.h57
-rw-r--r--libs/rs/rsScriptC.cpp529
-rw-r--r--libs/rs/rsScriptC.h84
-rw-r--r--libs/rs/rsThreadIO.cpp58
-rw-r--r--libs/rs/rsThreadIO.h57
-rw-r--r--libs/rs/rsTriangleMesh.cpp299
-rw-r--r--libs/rs/rsTriangleMesh.h92
-rw-r--r--libs/rs/rsType.cpp229
-rw-r--r--libs/rs/rsType.h134
-rw-r--r--libs/rs/rsUtils.h120
-rw-r--r--libs/rs/rsgApi.cpp.rsg1
-rw-r--r--libs/rs/rsgApiFuncDecl.h.rsg1
-rw-r--r--libs/rs/rsgApiReplay.cpp.rsg1
-rw-r--r--libs/rs/rsgApiStructs.h.rsg1
-rw-r--r--libs/rs/rsg_generator.c291
-rw-r--r--libs/rs/spec.lex171
-rw-r--r--libs/surfaceflinger/Android.mk1
-rw-r--r--libs/surfaceflinger/GPUHardware/GPUHardware.cpp12
-rw-r--r--libs/surfaceflinger/LayerBitmap.cpp4
-rw-r--r--libs/surfaceflinger/LayerBuffer.cpp4
-rw-r--r--libs/surfaceflinger/LayerBuffer.h2
-rw-r--r--libs/surfaceflinger/LayerOrientationAnim.h2
-rw-r--r--libs/surfaceflinger/LayerOrientationAnimRotate.h2
-rw-r--r--libs/surfaceflinger/LayerScreenshot.cpp110
-rw-r--r--libs/surfaceflinger/SurfaceFlinger.cpp9
-rw-r--r--libs/surfaceflinger/SurfaceFlinger.h2
-rw-r--r--libs/surfaceflinger/VRamHeap.cpp8
-rw-r--r--libs/surfaceflinger/VRamHeap.h2
-rw-r--r--libs/surfaceflinger/tests/overlays/overlays.cpp6
-rw-r--r--libs/ui/Android.mk1
-rw-r--r--libs/ui/Camera.cpp4
-rw-r--r--libs/ui/EventHub.cpp5
-rw-r--r--libs/ui/ICamera.cpp8
-rw-r--r--libs/ui/ICameraClient.cpp6
-rw-r--r--libs/ui/ICameraService.cpp12
-rw-r--r--libs/ui/IOverlay.cpp10
-rw-r--r--libs/ui/ISurface.cpp10
-rw-r--r--libs/ui/ISurfaceComposer.cpp33
-rw-r--r--libs/ui/ISurfaceFlingerClient.cpp14
-rw-r--r--libs/ui/LayerState.cpp2
-rw-r--r--libs/ui/Overlay.cpp6
-rw-r--r--libs/ui/Surface.cpp4
-rw-r--r--libs/ui/SurfaceComposerClient.cpp8
-rw-r--r--libs/ui/SurfaceFlingerSynchro.cpp2
-rw-r--r--libs/utils/Android.mk50
-rw-r--r--libs/utils/CallStack.cpp3
-rw-r--r--libs/utils/IDataConnection.cpp89
-rw-r--r--libs/utils/InetAddress.cpp236
-rw-r--r--libs/utils/LogSocket.cpp129
-rw-r--r--libs/utils/Pipe.cpp465
-rw-r--r--libs/utils/Socket.cpp388
-rw-r--r--libs/utils/Static.cpp31
-rw-r--r--libs/utils/StringArray.cpp113
-rw-r--r--libs/utils/TextOutput.cpp10
-rw-r--r--libs/utils/TimerProbe.cpp131
-rw-r--r--libs/utils/Timers.cpp125
-rw-r--r--libs/utils/ported.cpp106
-rw-r--r--location/java/android/location/Geocoder.java6
-rw-r--r--location/java/com/android/internal/location/GpsXtraDownloader.java1
-rw-r--r--media/java/android/media/MediaScanner.java12
-rw-r--r--media/java/android/media/RingtoneManager.java32
-rw-r--r--media/jni/Android.mk1
-rw-r--r--media/jni/soundpool/Android.mk1
-rw-r--r--media/libdrm/mobile2/include/rights/RoManager.h6
-rw-r--r--media/libdrm/mobile2/src/rights/RoManager.cpp6
-rw-r--r--media/libmedia/Android.mk2
-rw-r--r--media/libmedia/AudioRecord.cpp8
-rw-r--r--media/libmedia/AudioSystem.cpp2
-rw-r--r--media/libmedia/AudioTrack.cpp6
-rw-r--r--media/libmedia/IAudioFlinger.cpp8
-rw-r--r--media/libmedia/IAudioFlingerClient.cpp8
-rw-r--r--media/libmedia/IAudioRecord.cpp8
-rw-r--r--media/libmedia/IAudioTrack.cpp8
-rw-r--r--media/libmedia/IMediaMetadataRetriever.cpp8
-rw-r--r--media/libmedia/IMediaPlayer.cpp8
-rw-r--r--media/libmedia/IMediaPlayerClient.cpp10
-rw-r--r--media/libmedia/IMediaPlayerService.cpp10
-rw-r--r--media/libmedia/IMediaRecorder.cpp8
-rw-r--r--media/libmedia/mediametadataretriever.cpp4
-rw-r--r--media/libmedia/mediaplayer.cpp6
-rw-r--r--media/libmedia/mediarecorder.cpp2
-rw-r--r--media/libmediaplayerservice/Android.mk1
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp14
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h5
-rw-r--r--media/libmediaplayerservice/MediaRecorderClient.cpp8
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.cpp10
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.h7
-rw-r--r--media/mediaserver/Android.mk3
-rw-r--r--media/mediaserver/main_mediaserver.cpp6
-rw-r--r--media/sdutils/sdutil.cpp4
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java10
-rw-r--r--opengl/libs/Android.mk2
-rw-r--r--opengl/libs/EGL/gpu.cpp8
-rw-r--r--packages/SettingsProvider/etc/bookmarks.xml4
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java2
-rw-r--r--packages/SubscribedFeedsProvider/AndroidManifest.xml2
-rw-r--r--packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java61
-rw-r--r--packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java15
-rw-r--r--preloaded-classes8
-rw-r--r--services/java/com/android/server/BatteryService.java19
-rw-r--r--services/java/com/android/server/InputDevice.java6
-rw-r--r--services/java/com/android/server/KeyInputQueue.java46
-rw-r--r--services/java/com/android/server/MasterClearReceiver.java4
-rw-r--r--services/java/com/android/server/PackageManagerService.java3
-rw-r--r--services/java/com/android/server/SystemServer.java16
-rw-r--r--services/java/com/android/server/WifiService.java15
-rw-r--r--services/java/com/android/server/WindowManagerService.java67
-rw-r--r--services/java/com/android/server/status/StatusBarPolicy.java79
-rw-r--r--services/jni/com_android_server_AlarmManagerService.cpp4
-rw-r--r--services/jni/com_android_server_BatteryService.cpp4
-rw-r--r--telephony/java/android/telephony/PhoneNumberUtils.java5
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneBase.java32
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/MccTable.java59
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SIMRecords.java26
-rw-r--r--test-runner/android/test/IsolatedContext.java21
-rw-r--r--test-runner/android/test/SyncBaseInstrumentation.java8
-rw-r--r--test-runner/android/test/mock/MockContentProvider.java32
-rw-r--r--test-runner/android/test/mock/MockPackageManager.java3
-rwxr-xr-xtests/AndroidTests/run_test.sh2
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java181
-rw-r--r--tests/CoreTests/android/content/SyncStorageEngineTest.java3
-rw-r--r--tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java5
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java11
-rw-r--r--tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java35
-rw-r--r--tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java468
-rw-r--r--tools/aapt/AaptAssets.h20
-rw-r--r--tools/aapt/Android.mk5
-rw-r--r--tools/aapt/Bundle.h5
-rw-r--r--tools/aapt/Command.cpp6
-rw-r--r--tools/aapt/Images.cpp5
-rw-r--r--tools/aapt/Main.cpp6
-rw-r--r--tools/aapt/Main.h7
-rw-r--r--tools/aapt/Package.cpp6
-rw-r--r--tools/aapt/Resource.cpp9
-rw-r--r--tools/aapt/XMLNode.cpp1
-rw-r--r--tools/aapt/ZipEntry.cpp (renamed from libs/utils/ZipEntry.cpp)2
-rw-r--r--tools/aapt/ZipEntry.h (renamed from include/utils/ZipEntry.h)2
-rw-r--r--tools/aapt/ZipFile.cpp (renamed from libs/utils/ZipFile.cpp)205
-rw-r--r--tools/aapt/ZipFile.h (renamed from include/utils/ZipFile.h)7
-rwxr-xr-xtools/aidl/AST.cpp17
-rwxr-xr-xtools/aidl/AST.h1
-rw-r--r--tools/aidl/generate_java.cpp7
-rw-r--r--tools/aidl/options.h1
-rw-r--r--tools/localize/Perforce.cpp3
-rw-r--r--tools/localize/SourcePos.cpp1
-rw-r--r--tools/localize/Values.cpp1
-rw-r--r--tools/localize/XLIFFFile.cpp1
-rw-r--r--tools/localize/XMLHandler.h1
-rw-r--r--tools/localize/file_utils.cpp3
-rw-r--r--tools/localize/file_utils.h1
-rw-r--r--tools/localize/localize.cpp1
-rw-r--r--tools/localize/localize_test.cpp1
-rw-r--r--tools/localize/merge_res_and_xliff_test.cpp1
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl2
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java5
-rw-r--r--wifi/java/android/net/wifi/WifiStateTracker.java12
454 files changed, 27900 insertions, 7980 deletions
diff --git a/Android.mk b/Android.mk
index 26bcb5c..1f4a375 100644
--- a/Android.mk
+++ b/Android.mk
@@ -65,8 +65,11 @@ endif
## READ ME: ########################################################
LOCAL_SRC_FILES += \
core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \
- core/java/android/accessibilityservice/IEventListener.aidl \
- core/java/android/accounts/IAccountsService.aidl \
+ core/java/android/accessibilityservice/IEventListener.aidl \
+ core/java/android/accounts/IAccountManager.aidl \
+ core/java/android/accounts/IAccountManagerResponse.aidl \
+ core/java/android/accounts/IAccountAuthenticator.aidl \
+ core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
core/java/android/app/IActivityPendingResult.aidl \
core/java/android/app/IActivityWatcher.aidl \
core/java/android/app/IAlarmManager.aidl \
@@ -87,10 +90,10 @@ LOCAL_SRC_FILES += \
core/java/android/bluetooth/IBluetoothDevice.aidl \
core/java/android/bluetooth/IBluetoothDeviceCallback.aidl \
core/java/android/bluetooth/IBluetoothHeadset.aidl \
- core/java/android/content/IContentService.aidl \
+ core/java/android/content/IContentService.aidl \
core/java/android/content/ISyncAdapter.aidl \
core/java/android/content/ISyncContext.aidl \
- core/java/android/content/ISyncStatusObserver.aidl \
+ core/java/android/content/ISyncStatusObserver.aidl \
core/java/android/content/pm/IPackageDataObserver.aidl \
core/java/android/content/pm/IPackageDeleteObserver.aidl \
core/java/android/content/pm/IPackageInstallObserver.aidl \
@@ -190,7 +193,10 @@ framework_built := $(LOCAL_BUILT_MODULE)
# relative to the root of the build tree.
# ============================================================
aidl_files := \
- frameworks/base/core/java/android/accounts/IAccountsService.aidl \
+ frameworks/base/core/java/android/accounts/IAccountManager.aidl \
+ frameworks/base/core/java/android/accounts/IAccountManagerResponse.aidl \
+ frameworks/base/core/java/android/accounts/IAccountAuthenticator.aidl \
+ frameworks/base/core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
frameworks/base/core/java/android/app/Notification.aidl \
frameworks/base/core/java/android/app/PendingIntent.aidl \
frameworks/base/core/java/android/content/ComponentName.aidl \
diff --git a/api/current.xml b/api/current.xml
index c98a5c4..4203102 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -1420,7 +1420,7 @@
type="int"
transient="false"
volatile="false"
- value="17432583"
+ value="17432609"
static="true"
final="true"
deprecated="not deprecated"
@@ -1431,7 +1431,7 @@
type="int"
transient="false"
volatile="false"
- value="17432585"
+ value="17432611"
static="true"
final="true"
deprecated="not deprecated"
@@ -1442,7 +1442,7 @@
type="int"
transient="false"
volatile="false"
- value="17432586"
+ value="17432612"
static="true"
final="true"
deprecated="not deprecated"
@@ -1614,6 +1614,61 @@
visibility="public"
>
</field>
+<field name="donut_resource_pad22"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17432587"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="donut_resource_pad23"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17432586"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="donut_resource_pad24"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17432585"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="donut_resource_pad25"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17432584"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="donut_resource_pad26"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17432583"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="donut_resource_pad3"
type="int"
transient="false"
@@ -1717,7 +1772,7 @@
type="int"
transient="false"
volatile="false"
- value="17432587"
+ value="17432613"
static="true"
final="true"
deprecated="not deprecated"
@@ -1728,7 +1783,7 @@
type="int"
transient="false"
volatile="false"
- value="17432584"
+ value="17432610"
static="true"
final="true"
deprecated="not deprecated"
@@ -1989,6 +2044,17 @@
visibility="public"
>
</field>
+<field name="accountType"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843424"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="action"
type="int"
transient="false"
@@ -2957,6 +3023,17 @@
visibility="public"
>
</field>
+<field name="contentAuthority"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843425"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="contentDescription"
type="int"
transient="false"
@@ -10813,6 +10890,28 @@
visibility="public"
>
</field>
+<field name="donut_resource_pad41"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301672"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="donut_resource_pad42"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301671"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="donut_resource_pad5"
type="int"
transient="false"
@@ -12203,7 +12302,7 @@
type="int"
transient="false"
volatile="false"
- value="17301671"
+ value="17301713"
static="true"
final="true"
deprecated="not deprecated"
@@ -12214,7 +12313,7 @@
type="int"
transient="false"
volatile="false"
- value="17301672"
+ value="17301714"
static="true"
final="true"
deprecated="not deprecated"
@@ -15813,6 +15912,2004 @@
</field>
</class>
</package>
+<package name="android.accounts"
+>
+<class name="AbstractAccountAuthenticator"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AbstractAccountAuthenticator"
+ type="android.accounts.AbstractAccountAuthenticator"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="addAccount"
+ return="android.os.Bundle"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.AccountAuthenticatorResponse">
+</parameter>
+<parameter name="accountType" type="java.lang.String">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="requiredFeatures" type="java.lang.String[]">
+</parameter>
+<parameter name="options" type="android.os.Bundle">
+</parameter>
+<exception name="NetworkErrorException" type="android.accounts.NetworkErrorException">
+</exception>
+</method>
+<method name="confirmCredentials"
+ return="android.os.Bundle"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.AccountAuthenticatorResponse">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+</method>
+<method name="confirmPassword"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.AccountAuthenticatorResponse">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="password" type="java.lang.String">
+</parameter>
+<exception name="NetworkErrorException" type="android.accounts.NetworkErrorException">
+</exception>
+</method>
+<method name="editProperties"
+ return="android.os.Bundle"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.AccountAuthenticatorResponse">
+</parameter>
+<parameter name="accountType" type="java.lang.String">
+</parameter>
+</method>
+<method name="getAuthToken"
+ return="android.os.Bundle"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.AccountAuthenticatorResponse">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="loginOptions" type="android.os.Bundle">
+</parameter>
+<exception name="NetworkErrorException" type="android.accounts.NetworkErrorException">
+</exception>
+</method>
+<method name="getIAccountAuthenticator"
+ return="android.accounts.IAccountAuthenticator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hasFeatures"
+ return="android.os.Bundle"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.AccountAuthenticatorResponse">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="features" type="java.lang.String[]">
+</parameter>
+<exception name="NetworkErrorException" type="android.accounts.NetworkErrorException">
+</exception>
+</method>
+<method name="updateCredentials"
+ return="android.os.Bundle"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.AccountAuthenticatorResponse">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="loginOptions" type="android.os.Bundle">
+</parameter>
+</method>
+</class>
+<class name="Account"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="Account"
+ type="android.accounts.Account"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+<parameter name="type" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="Account"
+ type="android.accounts.Account"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="in" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mName"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="mType"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="AccountAuthenticatorActivity"
+ extends="android.app.Activity"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AccountAuthenticatorActivity"
+ type="android.accounts.AccountAuthenticatorActivity"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="setAccountAuthenticatorResult"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="result" type="android.os.Bundle">
+</parameter>
+</method>
+</class>
+<class name="AccountAuthenticatorResponse"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="AccountAuthenticatorResponse"
+ type="android.accounts.AccountAuthenticatorResponse"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.IAccountAuthenticatorResponse">
+</parameter>
+</constructor>
+<constructor name="AccountAuthenticatorResponse"
+ type="android.accounts.AccountAuthenticatorResponse"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parcel" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onError"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="errorCode" type="int">
+</parameter>
+<parameter name="errorMessage" type="java.lang.String">
+</parameter>
+</method>
+<method name="onRequestContinued"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onResult"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="result" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="AccountManager"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="addAccount"
+ return="android.accounts.Future2"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accountType" type="java.lang.String">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="requiredFeatures" type="java.lang.String[]">
+</parameter>
+<parameter name="addAccountOptions" type="android.os.Bundle">
+</parameter>
+<parameter name="activity" type="android.app.Activity">
+</parameter>
+<parameter name="callback" type="android.accounts.Future2Callback">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="addAccountExplicitly"
+ return="android.accounts.Future1&lt;java.lang.Boolean&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.Boolean&gt;">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="password" type="java.lang.String">
+</parameter>
+<parameter name="extras" type="android.os.Bundle">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="addOnAccountsUpdatedListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.accounts.OnAccountsUpdatedListener">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+<parameter name="updateImmediately" type="boolean">
+</parameter>
+</method>
+<method name="blockingAddAccountExplicitly"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="password" type="java.lang.String">
+</parameter>
+<parameter name="extras" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="blockingClearPassword"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+</method>
+<method name="blockingGetAccounts"
+ return="android.accounts.Account[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="blockingGetAccountsByType"
+ return="android.accounts.Account[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accountType" type="java.lang.String">
+</parameter>
+</method>
+<method name="blockingGetAccountsWithTypeAndFeatures"
+ return="android.accounts.Account[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="java.lang.String">
+</parameter>
+<parameter name="features" type="java.lang.String[]">
+</parameter>
+<exception name="AuthenticatorException" type="android.accounts.AuthenticatorException">
+</exception>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException">
+</exception>
+</method>
+<method name="blockingGetAuthToken"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="notifyAuthFailure" type="boolean">
+</parameter>
+<exception name="AuthenticatorException" type="android.accounts.AuthenticatorException">
+</exception>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException">
+</exception>
+</method>
+<method name="blockingGetAuthenticatorTypes"
+ return="java.lang.String[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="blockingGetPassword"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+</method>
+<method name="blockingGetUserData"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="key" type="java.lang.String">
+</parameter>
+</method>
+<method name="blockingInvalidateAuthToken"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accountType" type="java.lang.String">
+</parameter>
+<parameter name="authToken" type="java.lang.String">
+</parameter>
+</method>
+<method name="blockingPeekAuthToken"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+</method>
+<method name="blockingRemoveAccount"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+</method>
+<method name="blockingSetAuthToken"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="authToken" type="java.lang.String">
+</parameter>
+</method>
+<method name="blockingSetPassword"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="password" type="java.lang.String">
+</parameter>
+</method>
+<method name="blockingSetUserData"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="key" type="java.lang.String">
+</parameter>
+<parameter name="value" type="java.lang.String">
+</parameter>
+</method>
+<method name="clearPassword"
+ return="android.accounts.Future1&lt;java.lang.Void&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.Void&gt;">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="confirmCredentials"
+ return="android.accounts.Future2"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="activity" type="android.app.Activity">
+</parameter>
+<parameter name="callback" type="android.accounts.Future2Callback">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="confirmPassword"
+ return="android.accounts.Future1&lt;java.lang.Boolean&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="password" type="java.lang.String">
+</parameter>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.Boolean&gt;">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="editProperties"
+ return="android.accounts.Future2"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accountType" type="java.lang.String">
+</parameter>
+<parameter name="activity" type="android.app.Activity">
+</parameter>
+<parameter name="callback" type="android.accounts.Future2Callback">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="get"
+ return="android.accounts.AccountManager"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="getAccounts"
+ return="android.accounts.Future1&lt;android.accounts.Account[]&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;android.accounts.Account[]&gt;">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="getAccountsByType"
+ return="android.accounts.Future1&lt;android.accounts.Account[]&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;android.accounts.Account[]&gt;">
+</parameter>
+<parameter name="type" type="java.lang.String">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="getAccountsWithTypeAndFeatures"
+ return="android.accounts.Future2"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="java.lang.String">
+</parameter>
+<parameter name="features" type="java.lang.String[]">
+</parameter>
+<parameter name="callback" type="android.accounts.Future2Callback">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="getAuthToken"
+ return="android.accounts.Future2"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="loginOptions" type="android.os.Bundle">
+</parameter>
+<parameter name="activity" type="android.app.Activity">
+</parameter>
+<parameter name="callback" type="android.accounts.Future2Callback">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="getAuthToken"
+ return="android.accounts.Future2"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="notifyAuthFailure" type="boolean">
+</parameter>
+<parameter name="callback" type="android.accounts.Future2Callback">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="getAuthTokenByFeatures"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accountType" type="java.lang.String">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="features" type="java.lang.String[]">
+</parameter>
+<parameter name="activityForPrompting" type="android.app.Activity">
+</parameter>
+<parameter name="addAccountOptions" type="android.os.Bundle">
+</parameter>
+<parameter name="loginOptions" type="android.os.Bundle">
+</parameter>
+<parameter name="callback" type="android.accounts.Future2Callback">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="getAuthenticatorTypes"
+ return="android.accounts.Future1&lt;java.lang.String[]&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.String[]&gt;">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="getPassword"
+ return="android.accounts.Future1&lt;java.lang.String&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.String&gt;">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="getUserData"
+ return="android.accounts.Future1&lt;java.lang.String&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.String&gt;">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="key" type="java.lang.String">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="invalidateAuthToken"
+ return="android.accounts.Future1&lt;java.lang.Void&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.Void&gt;">
+</parameter>
+<parameter name="accountType" type="java.lang.String">
+</parameter>
+<parameter name="authToken" type="java.lang.String">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="peekAuthToken"
+ return="android.accounts.Future1&lt;java.lang.String&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.String&gt;">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="removeAccount"
+ return="android.accounts.Future1&lt;java.lang.Void&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.Void&gt;">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="removeOnAccountsUpdatedListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.accounts.OnAccountsUpdatedListener">
+</parameter>
+</method>
+<method name="setAuthToken"
+ return="android.accounts.Future1&lt;java.lang.Void&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.Void&gt;">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="authToken" type="java.lang.String">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="setPassword"
+ return="android.accounts.Future1&lt;java.lang.Void&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.Void&gt;">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="password" type="java.lang.String">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="setUserData"
+ return="android.accounts.Future1&lt;java.lang.Void&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.accounts.Future1Callback&lt;java.lang.Void&gt;">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="key" type="java.lang.String">
+</parameter>
+<parameter name="value" type="java.lang.String">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="updateCredentials"
+ return="android.accounts.Future2"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="loginOptions" type="android.os.Bundle">
+</parameter>
+<parameter name="activity" type="android.app.Activity">
+</parameter>
+<parameter name="callback" type="android.accounts.Future2Callback">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+</class>
+<class name="AuthenticatorException"
+ extends="java.lang.Exception"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AuthenticatorException"
+ type="android.accounts.AuthenticatorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="AuthenticatorException"
+ type="android.accounts.AuthenticatorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="AuthenticatorException"
+ type="android.accounts.AuthenticatorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="AuthenticatorException"
+ type="android.accounts.AuthenticatorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
+<class name="ChooseAccountActivity"
+ extends="android.app.ListActivity"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="ChooseAccountActivity"
+ type="android.accounts.ChooseAccountActivity"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="onCreate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="savedInstanceState" type="android.os.Bundle">
+</parameter>
+</method>
+</class>
+<class name="Constants"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="ACCOUNTS_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;accounts&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACCOUNT_AUTHENTICATOR_RESPONSE_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;accountAuthenticatorResponse&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACCOUNT_MANAGER_RESPONSE_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;accountManagerResponse&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACCOUNT_NAME_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;authAccount&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACCOUNT_TYPE_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;accountType&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUTHENTICATOR_TYPES_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;authenticator_types&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUTHTOKEN_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;authtoken&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUTH_FAILED_MESSAGE_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;authFailedMessage&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="BOOLEAN_RESULT_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;booleanResult&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_BAD_ARGUMENTS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_CANCELED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_INVALID_RESPONSE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;errorCode&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_NETWORK_ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_REMOTE_EXCEPTION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_CODE_UNSUPPORTED_OPERATION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_MESSAGE_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;errorMessage&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="INTENT_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;intent&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="LOGIN_ACCOUNTS_CHANGED_ACTION"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.accounts.LOGIN_ACCOUNTS_CHANGED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PASSWORD_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;password&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="USERDATA_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;userdata&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<interface name="Future1"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.util.concurrent.Future">
+</implements>
+<method name="getResult"
+ return="V"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException">
+</exception>
+</method>
+<method name="getResult"
+ return="V"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException">
+</exception>
+</method>
+</interface>
+<interface name="Future1Callback"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="future" type="android.accounts.Future1&lt;V&gt;">
+</parameter>
+</method>
+</interface>
+<interface name="Future2"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.util.concurrent.Future">
+</implements>
+<method name="getResult"
+ return="android.os.Bundle"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="AuthenticatorException" type="android.accounts.AuthenticatorException">
+</exception>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException">
+</exception>
+</method>
+<method name="getResult"
+ return="android.os.Bundle"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="AuthenticatorException" type="android.accounts.AuthenticatorException">
+</exception>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException">
+</exception>
+</method>
+</interface>
+<interface name="Future2Callback"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="run"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="future" type="android.accounts.Future2">
+</parameter>
+</method>
+</interface>
+<interface name="IAccountAuthenticator"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.IInterface">
+</implements>
+<method name="addAccount"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.IAccountAuthenticatorResponse">
+</parameter>
+<parameter name="accountType" type="java.lang.String">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="requiredFeatures" type="java.lang.String[]">
+</parameter>
+<parameter name="options" type="android.os.Bundle">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="confirmCredentials"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.IAccountAuthenticatorResponse">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="confirmPassword"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.IAccountAuthenticatorResponse">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="password" type="java.lang.String">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="editProperties"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.IAccountAuthenticatorResponse">
+</parameter>
+<parameter name="accountType" type="java.lang.String">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="getAuthToken"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.IAccountAuthenticatorResponse">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="options" type="android.os.Bundle">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="hasFeatures"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.IAccountAuthenticatorResponse">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="features" type="java.lang.String[]">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="updateCredentials"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="response" type="android.accounts.IAccountAuthenticatorResponse">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+<parameter name="options" type="android.os.Bundle">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</interface>
+<class name="IAccountAuthenticator.Stub"
+ extends="android.os.Binder"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.accounts.IAccountAuthenticator">
+</implements>
+<constructor name="IAccountAuthenticator.Stub"
+ type="android.accounts.IAccountAuthenticator.Stub"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="asBinder"
+ return="android.os.IBinder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="asInterface"
+ return="android.accounts.IAccountAuthenticator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="obj" type="android.os.IBinder">
+</parameter>
+</method>
+<method name="onTransact"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="code" type="int">
+</parameter>
+<parameter name="data" type="android.os.Parcel">
+</parameter>
+<parameter name="reply" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</class>
+<interface name="IAccountAuthenticatorResponse"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.IInterface">
+</implements>
+<method name="onError"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="errorCode" type="int">
+</parameter>
+<parameter name="errorMessage" type="java.lang.String">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="onRequestContinued"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="onResult"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="android.os.Bundle">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</interface>
+<class name="IAccountAuthenticatorResponse.Stub"
+ extends="android.os.Binder"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.accounts.IAccountAuthenticatorResponse">
+</implements>
+<constructor name="IAccountAuthenticatorResponse.Stub"
+ type="android.accounts.IAccountAuthenticatorResponse.Stub"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="asBinder"
+ return="android.os.IBinder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="asInterface"
+ return="android.accounts.IAccountAuthenticatorResponse"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="obj" type="android.os.IBinder">
+</parameter>
+</method>
+<method name="onTransact"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="code" type="int">
+</parameter>
+<parameter name="data" type="android.os.Parcel">
+</parameter>
+<parameter name="reply" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</class>
+<class name="NetworkErrorException"
+ extends="java.lang.Exception"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="NetworkErrorException"
+ type="android.accounts.NetworkErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="NetworkErrorException"
+ type="android.accounts.NetworkErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="NetworkErrorException"
+ type="android.accounts.NetworkErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="NetworkErrorException"
+ type="android.accounts.NetworkErrorException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
+<interface name="OnAccountsUpdatedListener"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onAccountsUpdated"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accounts" type="android.accounts.Account[]">
+</parameter>
+</method>
+</interface>
+<class name="OperationCanceledException"
+ extends="java.lang.Exception"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="OperationCanceledException"
+ type="android.accounts.OperationCanceledException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="OperationCanceledException"
+ type="android.accounts.OperationCanceledException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="OperationCanceledException"
+ type="android.accounts.OperationCanceledException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="OperationCanceledException"
+ type="android.accounts.OperationCanceledException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
+</package>
<package name="android.app"
>
<class name="Activity"
@@ -25024,6 +27121,75 @@
</package>
<package name="android.content"
>
+<class name="AbstractCursorEntityIterator"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.content.EntityIterator">
+</implements>
+<constructor name="AbstractCursorEntityIterator"
+ type="android.content.AbstractCursorEntityIterator"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="db" type="android.database.sqlite.SQLiteDatabase">
+</parameter>
+<parameter name="entityCursor" type="android.database.Cursor">
+</parameter>
+</constructor>
+<method name="close"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hasNext"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="newEntityFromCursorLocked"
+ return="android.content.Entity"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cursor" type="android.database.Cursor">
+</parameter>
+</method>
+<method name="next"
+ return="android.content.Entity"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
<class name="ActivityNotFoundException"
extends="java.lang.RuntimeException"
abstract="false"
@@ -25853,6 +28019,21 @@
visibility="public"
>
</constructor>
+<method name="applyBatch"
+ return="android.content.ContentProviderResult[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="operations" type="java.util.ArrayList&lt;android.content.ContentProviderOperation&gt;">
+</parameter>
+<exception name="OperationApplicationException" type="android.content.OperationApplicationException">
+</exception>
+</method>
<method name="attachInfo"
return="void"
abstract="false"
@@ -25961,6 +28142,21 @@
<parameter name="values" type="android.content.ContentValues">
</parameter>
</method>
+<method name="insertEntity"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entity" type="android.content.Entity">
+</parameter>
+</method>
<method name="isTemporary"
return="boolean"
abstract="false"
@@ -26079,6 +28275,25 @@
<parameter name="sortOrder" type="java.lang.String">
</parameter>
</method>
+<method name="queryEntities"
+ return="android.content.EntityIterator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+<parameter name="sortOrder" type="java.lang.String">
+</parameter>
+</method>
<method name="setReadPermission"
return="void"
abstract="false"
@@ -26124,6 +28339,671 @@
<parameter name="selectionArgs" type="java.lang.String[]">
</parameter>
</method>
+<method name="updateEntity"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entity" type="android.content.Entity">
+</parameter>
+</method>
+</class>
+<class name="ContentProviderClient"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="applyBatch"
+ return="android.content.ContentProviderResult[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="operations" type="java.util.ArrayList&lt;android.content.ContentProviderOperation&gt;">
+</parameter>
+<exception name="OperationApplicationException" type="android.content.OperationApplicationException">
+</exception>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="bulkInsert"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="android.net.Uri">
+</parameter>
+<parameter name="initialValues" type="android.content.ContentValues[]">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="delete"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="android.net.Uri">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="getLocalContentProvider"
+ return="android.content.ContentProvider"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getType"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="android.net.Uri">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="insert"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="android.net.Uri">
+</parameter>
+<parameter name="initialValues" type="android.content.ContentValues">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="insertEntity"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entity" type="android.content.Entity">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="openAssetFile"
+ return="android.content.res.AssetFileDescriptor"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="android.net.Uri">
+</parameter>
+<parameter name="mode" type="java.lang.String">
+</parameter>
+<exception name="FileNotFoundException" type="java.io.FileNotFoundException">
+</exception>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="openFile"
+ return="android.os.ParcelFileDescriptor"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="android.net.Uri">
+</parameter>
+<parameter name="mode" type="java.lang.String">
+</parameter>
+<exception name="FileNotFoundException" type="java.io.FileNotFoundException">
+</exception>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="query"
+ return="android.database.Cursor"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="android.net.Uri">
+</parameter>
+<parameter name="projection" type="java.lang.String[]">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+<parameter name="sortOrder" type="java.lang.String">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="queryEntities"
+ return="android.content.EntityIterator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+<parameter name="sortOrder" type="java.lang.String">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="release"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="update"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="android.net.Uri">
+</parameter>
+<parameter name="values" type="android.content.ContentValues">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="updateEntity"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="entity" type="android.content.Entity">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</class>
+<class name="ContentProviderOperation"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<method name="apply"
+ return="android.content.ContentProviderResult"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="provider" type="android.content.ContentProvider">
+</parameter>
+<parameter name="backRefs" type="android.content.ContentProviderResult[]">
+</parameter>
+<parameter name="numBackRefs" type="int">
+</parameter>
+<exception name="OperationApplicationException" type="android.content.OperationApplicationException">
+</exception>
+</method>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getUri"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isReadOperation"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isWriteOperation"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="newCountQuery"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
+<method name="newDelete"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
+<method name="newInsert"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
+<method name="newUpdate"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
+<method name="resolveSelectionArgsBackReferences"
+ return="java.lang.String[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="backRefs" type="android.content.ContentProviderResult[]">
+</parameter>
+<parameter name="numBackRefs" type="int">
+</parameter>
+</method>
+<method name="resolveValueBackReferences"
+ return="android.content.ContentValues"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="backRefs" type="android.content.ContentProviderResult[]">
+</parameter>
+<parameter name="numBackRefs" type="int">
+</parameter>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="ContentProviderOperation.Builder"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="build"
+ return="android.content.ContentProviderOperation"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="withExpectedCount"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="count" type="int">
+</parameter>
+</method>
+<method name="withSelection"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+</method>
+<method name="withSelectionBackReference"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="selectionArgIndex" type="int">
+</parameter>
+<parameter name="previousResult" type="int">
+</parameter>
+</method>
+<method name="withValue"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+<parameter name="value" type="java.lang.Object">
+</parameter>
+</method>
+<method name="withValueBackReference"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="java.lang.String">
+</parameter>
+<parameter name="previousResult" type="int">
+</parameter>
+</method>
+<method name="withValueBackReferences"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="backReferences" type="android.content.ContentValues">
+</parameter>
+</method>
+<method name="withValues"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="values" type="android.content.ContentValues">
+</parameter>
+</method>
+</class>
+<class name="ContentProviderResult"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="ContentProviderResult"
+ type="android.content.ContentProviderResult"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</constructor>
+<constructor name="ContentProviderResult"
+ type="android.content.ContentProviderResult"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="count" type="int">
+</parameter>
+</constructor>
+<constructor name="ContentProviderResult"
+ type="android.content.ContentProviderResult"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="source" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="count"
+ type="java.lang.Integer"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="uri"
+ type="android.net.Uri"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="ContentQueryMap"
extends="java.util.Observable"
@@ -26227,6 +29107,51 @@
<parameter name="context" type="android.content.Context">
</parameter>
</constructor>
+<method name="acquireContentProviderClient"
+ return="android.content.ContentProviderClient"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
+<method name="acquireContentProviderClient"
+ return="android.content.ContentProviderClient"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+</method>
+<method name="applyBatch"
+ return="android.content.ContentProviderResult[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="authority" type="java.lang.String">
+</parameter>
+<parameter name="operations" type="java.util.ArrayList&lt;android.content.ContentProviderOperation&gt;">
+</parameter>
+<exception name="OperationApplicationException" type="android.content.OperationApplicationException">
+</exception>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
<method name="bulkInsert"
return="int"
abstract="false"
@@ -26434,6 +29359,27 @@
<parameter name="sortOrder" type="java.lang.String">
</parameter>
</method>
+<method name="queryEntities"
+ return="android.content.EntityIterator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+<parameter name="sortOrder" type="java.lang.String">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
<method name="registerContentObserver"
return="void"
abstract="false"
@@ -28168,6 +31114,17 @@
visibility="public"
>
</field>
+<field name="ACCOUNT_SERVICE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;account&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTIVITY_SERVICE"
type="java.lang.String"
transient="false"
@@ -29649,6 +32606,186 @@
</parameter>
</method>
</interface>
+<class name="Entity"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="Entity"
+ type="android.content.Entity"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="values" type="android.content.ContentValues">
+</parameter>
+</constructor>
+<method name="addSubValue"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="values" type="android.content.ContentValues">
+</parameter>
+</method>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getEntityValues"
+ return="android.content.ContentValues"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSubValues"
+ return="java.util.ArrayList&lt;android.content.Entity.NamedContentValues&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="Entity.NamedContentValues"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Entity.NamedContentValues"
+ type="android.content.Entity.NamedContentValues"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="values" type="android.content.ContentValues">
+</parameter>
+</constructor>
+<field name="uri"
+ type="android.net.Uri"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="values"
+ type="android.content.ContentValues"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<interface name="EntityIterator"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="close"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hasNext"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="next"
+ return="android.content.Entity"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</interface>
<class name="Intent"
extends="java.lang.Object"
abstract="false"
@@ -31702,7 +34839,7 @@
type="java.lang.String"
transient="false"
volatile="false"
- value="&quot;android.intent.action.ACTION_POWER_CONNECTED&quot;"
+ value="&quot;android.intent.action.POWER_CONNECTED&quot;"
static="true"
final="true"
deprecated="not deprecated"
@@ -31713,7 +34850,7 @@
type="java.lang.String"
transient="false"
volatile="false"
- value="&quot;android.intent.action.ACTION_POWER_DISCONNECTED&quot;"
+ value="&quot;android.intent.action.POWER_DISCONNECTED&quot;"
static="true"
final="true"
deprecated="not deprecated"
@@ -31742,6 +34879,17 @@
visibility="public"
>
</field>
+<field name="ACTION_REMOTE_INTENT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.REMOTE_INTENT&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_RUN"
type="java.lang.String"
transient="false"
@@ -32280,6 +35428,17 @@
visibility="public"
>
</field>
+<field name="EXTRA_REMOTE_INTENT_TOKEN"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.extra.remote_intent_token&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="EXTRA_REPLACING"
type="java.lang.String"
transient="false"
@@ -33700,6 +36859,55 @@
</parameter>
</method>
</class>
+<class name="OperationApplicationException"
+ extends="java.lang.Exception"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="OperationApplicationException"
+ type="android.content.OperationApplicationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="OperationApplicationException"
+ type="android.content.OperationApplicationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="OperationApplicationException"
+ type="android.content.OperationApplicationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+<constructor name="OperationApplicationException"
+ type="android.content.OperationApplicationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cause" type="java.lang.Throwable">
+</parameter>
+</constructor>
+</class>
<class name="ReceiverCallNotAllowedException"
extends="android.util.AndroidRuntimeException"
abstract="false"
@@ -34190,6 +37398,47 @@
</parameter>
</method>
</interface>
+<class name="SyncAdapterType"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SyncAdapterType"
+ type="android.content.SyncAdapterType"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="authority" type="java.lang.String">
+</parameter>
+<parameter name="accountType" type="java.lang.String">
+</parameter>
+</constructor>
+<field name="accountType"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="authority"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="UriMatcher"
extends="java.lang.Object"
abstract="false"
@@ -36215,6 +39464,19 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="getInstallerPackageName"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+</method>
<method name="getInstrumentationInfo"
return="android.content.pm.InstrumentationInfo"
abstract="true"
@@ -37575,7 +40837,7 @@
volatile="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -41269,6 +44531,32 @@
<parameter name="columnIndex" type="int">
</parameter>
</method>
+<method name="isFloat"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+</method>
+<method name="isLong"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+</method>
<method name="isNull"
return="boolean"
abstract="false"
@@ -41282,6 +44570,19 @@
<parameter name="columnIndex" type="int">
</parameter>
</method>
+<method name="isString"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="columnIndex" type="int">
+</parameter>
+</method>
<method name="setWindow"
return="void"
abstract="false"
@@ -42362,6 +45663,36 @@
<parameter name="col" type="int">
</parameter>
</method>
+<method name="isFloat"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="row" type="int">
+</parameter>
+<parameter name="col" type="int">
+</parameter>
+</method>
+<method name="isLong"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="row" type="int">
+</parameter>
+<parameter name="col" type="int">
+</parameter>
+</method>
<method name="isNull"
return="boolean"
abstract="false"
@@ -42377,6 +45708,21 @@
<parameter name="col" type="int">
</parameter>
</method>
+<method name="isString"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="row" type="int">
+</parameter>
+<parameter name="col" type="int">
+</parameter>
+</method>
<method name="newFromParcel"
return="android.database.CursorWindow"
abstract="false"
@@ -43572,6 +46918,21 @@
<exception name="FileNotFoundException" type="java.io.FileNotFoundException">
</exception>
</method>
+<method name="readExceptionWithOperationApplicationExceptionFromParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reply" type="android.os.Parcel">
+</parameter>
+<exception name="OperationApplicationException" type="android.content.OperationApplicationException">
+</exception>
+</method>
<method name="sqlEscapeString"
return="java.lang.String"
abstract="false"
@@ -101996,6 +105357,17 @@
visibility="public"
>
</field>
+<field name="GROUP_SYNC_ACCOUNT_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;group_sync_account_type&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="GROUP_SYNC_ID"
type="java.lang.String"
transient="false"
@@ -103938,6 +107310,17 @@
visibility="public"
>
</field>
+<field name="_SYNC_ACCOUNT_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;_sync_account_type&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</interface>
<class name="LiveFolders"
extends="java.lang.Object"
@@ -107912,6 +111295,17 @@
visibility="public"
>
</field>
+<field name="ALARM_ALERT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;alarm_alert&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ALWAYS_FINISH_ACTIVITIES"
type="java.lang.String"
transient="false"
@@ -108032,6 +111426,16 @@
visibility="public"
>
</field>
+<field name="DEFAULT_ALARM_ALERT_URI"
+ type="android.net.Uri"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="DEFAULT_NOTIFICATION_URI"
type="android.net.Uri"
transient="false"
@@ -116733,6 +120137,19 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="getInstallerPackageName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+</method>
<method name="getInstrumentationInfo"
return="android.content.pm.InstrumentationInfo"
abstract="false"
@@ -155739,6 +159156,25 @@
<parameter name="contentLength" type="long">
</parameter>
</method>
+<method name="onExceededDatabaseQuota"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="java.lang.String">
+</parameter>
+<parameter name="databaseIdentifier" type="java.lang.String">
+</parameter>
+<parameter name="currentQuota" type="long">
+</parameter>
+<parameter name="quotaUpdater" type="android.webkit.WebStorage.QuotaUpdater">
+</parameter>
+</method>
<method name="onFormResubmission"
return="void"
abstract="false"
@@ -157380,6 +160816,25 @@
<parameter name="resultMsg" type="android.os.Message">
</parameter>
</method>
+<method name="onExceededDatabaseQuota"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="java.lang.String">
+</parameter>
+<parameter name="databaseIdentifier" type="java.lang.String">
+</parameter>
+<parameter name="currentQuota" type="long">
+</parameter>
+<parameter name="quotaUpdater" type="android.webkit.WebStorage.QuotaUpdater">
+</parameter>
+</method>
<method name="onJsAlert"
return="boolean"
abstract="false"
@@ -157765,6 +161220,28 @@
visibility="public"
>
</method>
+<method name="getDatabaseEnabled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDatabasePath"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getDefaultFixedFontSize"
return="int"
abstract="false"
@@ -158003,7 +161480,7 @@
synchronized="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -158105,6 +161582,32 @@
<parameter name="font" type="java.lang.String">
</parameter>
</method>
+<method name="setDatabaseEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="flag" type="boolean">
+</parameter>
+</method>
+<method name="setDatabasePath"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="databasePath" type="java.lang.String">
+</parameter>
+</method>
<method name="setDefaultFixedFontSize"
return="void"
abstract="false"
@@ -158437,7 +161940,7 @@
synchronized="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="use" type="boolean">
@@ -158659,6 +162162,44 @@
>
</method>
</class>
+<class name="WebStorage"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="WebStorage"
+ type="android.webkit.WebStorage"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+</class>
+<interface name="WebStorage.QuotaUpdater"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="updateQuota"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="newQuota" type="long">
+</parameter>
+</method>
+</interface>
<class name="WebSyncManager"
extends="java.lang.Object"
abstract="true"
@@ -162819,6 +166360,39 @@
visibility="public"
>
</method>
+<method name="getDropDownBackground"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDropDownHorizontalOffset"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDropDownVerticalOffset"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getDropDownWidth"
return="int"
abstract="false"
@@ -163042,6 +166616,58 @@
<parameter name="id" type="int">
</parameter>
</method>
+<method name="setDropDownBackgroundDrawable"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="d" type="android.graphics.drawable.Drawable">
+</parameter>
+</method>
+<method name="setDropDownBackgroundResource"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+</method>
+<method name="setDropDownHorizontalOffset"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="offset" type="int">
+</parameter>
+</method>
+<method name="setDropDownVerticalOffset"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="offset" type="int">
+</parameter>
+</method>
<method name="setDropDownWidth"
return="void"
abstract="false"
diff --git a/camera/libcameraservice/Android.mk b/camera/libcameraservice/Android.mk
index 96cc512..be78a62 100644
--- a/camera/libcameraservice/Android.mk
+++ b/camera/libcameraservice/Android.mk
@@ -42,6 +42,7 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES:= \
libui \
libutils \
+ libbinder \
libcutils \
libmedia
diff --git a/camera/libcameraservice/CameraHardwareStub.h b/camera/libcameraservice/CameraHardwareStub.h
index 0d26d47..efae935 100644
--- a/camera/libcameraservice/CameraHardwareStub.h
+++ b/camera/libcameraservice/CameraHardwareStub.h
@@ -21,8 +21,8 @@
#include "FakeCamera.h"
#include <utils/threads.h>
#include <ui/CameraHardwareInterface.h>
-#include <utils/MemoryBase.h>
-#include <utils/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
#include <utils/threads.h>
namespace android {
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index 4e6859c..453dc29 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -20,12 +20,12 @@
#define LOG_TAG "CameraService"
#include <utils/Log.h>
-#include <utils/IServiceManager.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
#include <utils/String16.h>
#include <utils/Errors.h>
-#include <utils/MemoryBase.h>
-#include <utils/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
#include <ui/ICameraService.h>
#include <media/mediaplayer.h>
@@ -1052,12 +1052,6 @@ status_t CameraService::dump(int fd, const Vector<String16>& args)
}
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t CameraService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index d825d5a..7decf9a 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -7,8 +7,8 @@
#define LOG_TAG "appproc"
-#include <utils/IPCThreadState.h>
-#include <utils/ProcessState.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
#include <utils/Log.h>
#include <cutils/process_name.h>
#include <cutils/memory.h>
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 3b9db8d..d565dc1 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -22,7 +22,7 @@
#include <fcntl.h>
#include <utils/misc.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IPCThreadState.h>
#include <utils/threads.h>
#include <utils/Atomic.h>
#include <utils/Errors.h>
diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp
index 675ea81..346f156 100644
--- a/cmds/bootanimation/bootanimation_main.cpp
+++ b/cmds/bootanimation/bootanimation_main.cpp
@@ -16,9 +16,9 @@
#define LOG_TAG "BootAnimation"
-#include <utils/IPCThreadState.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <utils/threads.h>
diff --git a/cmds/dumpsys/Android.mk b/cmds/dumpsys/Android.mk
index 0c623cc..42b1b73 100644
--- a/cmds/dumpsys/Android.mk
+++ b/cmds/dumpsys/Android.mk
@@ -5,7 +5,9 @@ LOCAL_SRC_FILES:= \
dumpsys.cpp
LOCAL_SHARED_LIBRARIES := \
- libutils
+ libutils \
+ libbinder
+
ifeq ($(TARGET_OS),linux)
LOCAL_CFLAGS += -DXP_UNIX
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index a62fe55..945a690 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -6,9 +6,9 @@
#define LOG_TAG "dumpsys"
#include <utils/Log.h>
-#include <utils/Parcel.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <utils/TextOutput.h>
#include <utils/Vector.h>
diff --git a/cmds/runtime/Android.mk b/cmds/runtime/Android.mk
index 521eb2b..6a72d10 100644
--- a/cmds/runtime/Android.mk
+++ b/cmds/runtime/Android.mk
@@ -10,6 +10,7 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES := \
libutils \
+ libbinder \
libandroid_runtime \
libcutils \
libui \
diff --git a/cmds/runtime/ServiceManager.cpp b/cmds/runtime/ServiceManager.cpp
index 758a95c..b2bef07 100644
--- a/cmds/runtime/ServiceManager.cpp
+++ b/cmds/runtime/ServiceManager.cpp
@@ -9,9 +9,9 @@
#include <utils/Debug.h>
#include <utils/Log.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <utils/String8.h>
-#include <utils/ProcessState.h>
+#include <binder/ProcessState.h>
#include <private/utils/Static.h>
diff --git a/cmds/runtime/ServiceManager.h b/cmds/runtime/ServiceManager.h
index d09cec8..090ca6d 100644
--- a/cmds/runtime/ServiceManager.h
+++ b/cmds/runtime/ServiceManager.h
@@ -4,7 +4,7 @@
#ifndef ANDROID_SERVICE_MANAGER_H
#define ANDROID_SERVICE_MANAGER_H
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
diff --git a/cmds/runtime/main_runtime.cpp b/cmds/runtime/main_runtime.cpp
index 476f38a..21e0e4d 100644
--- a/cmds/runtime/main_runtime.cpp
+++ b/cmds/runtime/main_runtime.cpp
@@ -7,9 +7,11 @@
#include "ServiceManager.h"
#include "SignalHandler.h"
-#include <utils.h>
-#include <utils/IPCThreadState.h>
-#include <utils/ProcessState.h>
+#include <utils/threads.h>
+#include <utils/Errors.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
#include <utils/Log.h>
#include <cutils/zygote.h>
diff --git a/cmds/service/Android.mk b/cmds/service/Android.mk
index 8c5005c..275bbb2 100644
--- a/cmds/service/Android.mk
+++ b/cmds/service/Android.mk
@@ -4,8 +4,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
service.cpp
-LOCAL_SHARED_LIBRARIES := \
- libutils
+LOCAL_SHARED_LIBRARIES := libutils libbinder
ifeq ($(TARGET_OS),linux)
LOCAL_CFLAGS += -DXP_UNIX
diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp
index 859a9bf..32db83b 100644
--- a/cmds/service/service.cpp
+++ b/cmds/service/service.cpp
@@ -3,9 +3,9 @@
*
*/
-#include <utils/Parcel.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <utils/TextOutput.h>
#include <getopt.h>
diff --git a/cmds/surfaceflinger/Android.mk b/cmds/surfaceflinger/Android.mk
index 37c3d94..bfa58a1 100644
--- a/cmds/surfaceflinger/Android.mk
+++ b/cmds/surfaceflinger/Android.mk
@@ -6,6 +6,7 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES := \
libsurfaceflinger \
+ libbinder \
libutils
LOCAL_C_INCLUDES := \
diff --git a/cmds/surfaceflinger/main_surfaceflinger.cpp b/cmds/surfaceflinger/main_surfaceflinger.cpp
index 7c89578..d650721 100644
--- a/cmds/surfaceflinger/main_surfaceflinger.cpp
+++ b/cmds/surfaceflinger/main_surfaceflinger.cpp
@@ -1,6 +1,6 @@
-#include <utils/IPCThreadState.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <SurfaceFlinger.h>
diff --git a/cmds/system_server/Android.mk b/cmds/system_server/Android.mk
index 0a684e8..ad537977 100644
--- a/cmds/system_server/Android.mk
+++ b/cmds/system_server/Android.mk
@@ -6,6 +6,7 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES := \
libutils \
+ libbinder \
libsystem_server
LOCAL_C_INCLUDES := \
diff --git a/cmds/system_server/library/Android.mk b/cmds/system_server/library/Android.mk
index 580331a..1813d3e 100644
--- a/cmds/system_server/library/Android.mk
+++ b/cmds/system_server/library/Android.mk
@@ -20,6 +20,7 @@ LOCAL_SHARED_LIBRARIES := \
libcameraservice \
libmediaplayerservice \
libutils \
+ libbinder \
libcutils
LOCAL_MODULE:= libsystem_server
diff --git a/cmds/system_server/library/system_init.cpp b/cmds/system_server/library/system_init.cpp
index 73b23e2..ea78461 100644
--- a/cmds/system_server/library/system_init.cpp
+++ b/cmds/system_server/library/system_init.cpp
@@ -8,9 +8,9 @@
#define LOG_TAG "sysproc"
-#include <utils/IPCThreadState.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <utils/TextOutput.h>
#include <utils/Log.h>
diff --git a/cmds/system_server/system_main.cpp b/cmds/system_server/system_main.cpp
index ca16e57..543f650 100644
--- a/cmds/system_server/system_main.cpp
+++ b/cmds/system_server/system_main.cpp
@@ -9,7 +9,7 @@
#define LOG_TAG "sysproc"
-#include <utils/IPCThreadState.h>
+#include <binder/IPCThreadState.h>
#include <utils/Log.h>
#include <private/android_filesystem_config.h>
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
new file mode 100644
index 0000000..474755c
--- /dev/null
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -0,0 +1,196 @@
+/*
+ * 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.accounts;
+
+import android.os.Bundle;
+import android.os.RemoteException;
+
+/**
+ * Base class for creating AccountAuthenticators. This implements the IAccountAuthenticator
+ * binder interface and also provides helper libraries to simplify the creation of
+ * AccountAuthenticators.
+ */
+public abstract class AbstractAccountAuthenticator {
+ class Transport extends IAccountAuthenticator.Stub {
+ public void addAccount(IAccountAuthenticatorResponse response, String accountType,
+ String authTokenType, String[] requiredFeatures, Bundle options)
+ throws RemoteException {
+ final Bundle result;
+ try {
+ result = AbstractAccountAuthenticator.this.addAccount(
+ new AccountAuthenticatorResponse(response),
+ accountType, authTokenType, requiredFeatures, options);
+ } catch (NetworkErrorException e) {
+ response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
+ return;
+ } catch (UnsupportedOperationException e) {
+ response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "addAccount not supported");
+ return;
+ }
+ if (result != null) {
+ response.onResult(result);
+ }
+ }
+
+ public void confirmPassword(IAccountAuthenticatorResponse response,
+ Account account, String password) throws RemoteException {
+ boolean result;
+ try {
+ result = AbstractAccountAuthenticator.this.confirmPassword(
+ new AccountAuthenticatorResponse(response),
+ account, password);
+ } catch (UnsupportedOperationException e) {
+ response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "confirmPassword not supported");
+ return;
+ } catch (NetworkErrorException e) {
+ response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
+ return;
+ }
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(Constants.BOOLEAN_RESULT_KEY, result);
+ response.onResult(bundle);
+ }
+
+ public void confirmCredentials(IAccountAuthenticatorResponse response,
+ Account account) throws RemoteException {
+ final Bundle result;
+ try {
+ result = AbstractAccountAuthenticator.this.confirmCredentials(
+ new AccountAuthenticatorResponse(response), account);
+ } catch (UnsupportedOperationException e) {
+ response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "confirmCredentials not supported");
+ return;
+ }
+ if (result != null) {
+ response.onResult(result);
+ }
+ }
+
+ public void getAuthToken(IAccountAuthenticatorResponse response,
+ Account account, String authTokenType, Bundle loginOptions)
+ throws RemoteException {
+ try {
+ final Bundle result = AbstractAccountAuthenticator.this.getAuthToken(
+ new AccountAuthenticatorResponse(response), account,
+ authTokenType, loginOptions);
+ if (result != null) {
+ response.onResult(result);
+ }
+ } catch (UnsupportedOperationException e) {
+ response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "getAuthToken not supported");
+ } catch (NetworkErrorException e) {
+ response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
+ }
+ }
+
+ public void updateCredentials(IAccountAuthenticatorResponse response, Account account,
+ String authTokenType, Bundle loginOptions) throws RemoteException {
+ final Bundle result;
+ try {
+ result = AbstractAccountAuthenticator.this.updateCredentials(
+ new AccountAuthenticatorResponse(response), account,
+ authTokenType, loginOptions);
+ } catch (UnsupportedOperationException e) {
+ response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "updateCredentials not supported");
+ return;
+ }
+ if (result != null) {
+ response.onResult(result);
+ }
+ }
+
+ public void editProperties(IAccountAuthenticatorResponse response,
+ String accountType) throws RemoteException {
+ final Bundle result;
+ try {
+ result = AbstractAccountAuthenticator.this.editProperties(
+ new AccountAuthenticatorResponse(response), accountType);
+ } catch (UnsupportedOperationException e) {
+ response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "editProperties not supported");
+ return;
+ }
+ if (result != null) {
+ response.onResult(result);
+ }
+ }
+
+ public void hasFeatures(IAccountAuthenticatorResponse response,
+ Account account, String[] features) throws RemoteException {
+ final Bundle result;
+ try {
+ result = AbstractAccountAuthenticator.this.hasFeatures(
+ new AccountAuthenticatorResponse(response), account, features);
+ } catch (UnsupportedOperationException e) {
+ response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "hasFeatures not supported");
+ return;
+ } catch (NetworkErrorException e) {
+ response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
+ return;
+ }
+ if (result != null) {
+ response.onResult(result);
+ }
+ }
+ }
+
+ Transport mTransport = new Transport();
+
+ /**
+ * @return the IAccountAuthenticator binder transport object
+ */
+ public final IAccountAuthenticator getIAccountAuthenticator()
+ {
+ return mTransport;
+ }
+
+ /**
+ * Returns a Bundle that contains the Intent of the activity that can be used to edit the
+ * properties. In order to indicate success the activity should call response.setResult()
+ * with a non-null Bundle.
+ * @param response used to set the result for the request. If the Constants.INTENT_KEY
+ * is set in the bundle then this response field is to be used for sending future
+ * results if and when the Intent is started.
+ * @param accountType the AccountType whose properties are to be edited.
+ * @return a Bundle containing the result or the Intent to start to continue the request.
+ * If this is null then the request is considered to still be active and the result should
+ * sent later using response.
+ */
+ public abstract Bundle editProperties(AccountAuthenticatorResponse response,
+ String accountType);
+ public abstract Bundle addAccount(AccountAuthenticatorResponse response, String accountType,
+ String authTokenType, String[] requiredFeatures, Bundle options)
+ throws NetworkErrorException;
+ /* @deprecated */
+ public abstract boolean confirmPassword(AccountAuthenticatorResponse response,
+ Account account, String password) throws NetworkErrorException;
+ public abstract Bundle confirmCredentials(AccountAuthenticatorResponse response,
+ Account account);
+ public abstract Bundle getAuthToken(AccountAuthenticatorResponse response,
+ Account account, String authTokenType, Bundle loginOptions)
+ throws NetworkErrorException;
+ public abstract Bundle updateCredentials(AccountAuthenticatorResponse response,
+ Account account, String authTokenType, Bundle loginOptions);
+ public abstract Bundle hasFeatures(AccountAuthenticatorResponse response,
+ Account account, String[] features) throws NetworkErrorException;
+}
diff --git a/include/utils/executablepath.h b/core/java/android/accounts/Account.aidl
index c979432..8752d99 100644
--- a/include/utils/executablepath.h
+++ b/core/java/android/accounts/Account.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * 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.
@@ -14,15 +14,6 @@
* limitations under the License.
*/
-#ifndef _UTILS_EXECUTABLEPATH_H
-#define _UTILS_EXECUTABLEPATH_H
+package android.accounts;
-#include <limits.h>
-
-// returns the path to this executable
-#if __cplusplus
-extern "C"
-#endif
-void executablepath(char s[PATH_MAX]);
-
-#endif // _UTILS_EXECUTABLEPATH_H
+parcelable Account;
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
new file mode 100644
index 0000000..30c91b0
--- /dev/null
+++ b/core/java/android/accounts/Account.java
@@ -0,0 +1,84 @@
+/*
+ * 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.accounts;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.text.TextUtils;
+
+/**
+ * Value type that represents an Account in the {@link AccountManager}. This object is
+ * {@link Parcelable} and also overrides {@link #equals} and {@link #hashCode}, making it
+ * suitable for use as the key of a {@link java.util.Map}
+ */
+public class Account implements Parcelable {
+ public final String mName;
+ public final String mType;
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (!(o instanceof Account)) return false;
+ final Account other = (Account)o;
+ return mName.equals(other.mName) && mType.equals(other.mType);
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + mName.hashCode();
+ result = 31 * result + mType.hashCode();
+ return result;
+ }
+
+ public Account(String name, String type) {
+ if (TextUtils.isEmpty(name)) {
+ throw new IllegalArgumentException("the name must not be empty: " + name);
+ }
+ if (TextUtils.isEmpty(type)) {
+ throw new IllegalArgumentException("the type must not be empty: " + type);
+ }
+ mName = name;
+ mType = type;
+ }
+
+ public Account(Parcel in) {
+ mName = in.readString();
+ mType = in.readString();
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mName);
+ dest.writeString(mType);
+ }
+
+ public static final Creator<Account> CREATOR = new Creator<Account>() {
+ public Account createFromParcel(Parcel source) {
+ return new Account(source);
+ }
+
+ public Account[] newArray(int size) {
+ return new Account[size];
+ }
+ };
+
+ public String toString() {
+ return "Account {name=" + mName + ", type=" + mType + "}";
+ }
+}
diff --git a/core/java/android/accounts/AccountAuthenticatorActivity.java b/core/java/android/accounts/AccountAuthenticatorActivity.java
new file mode 100644
index 0000000..0319ab9
--- /dev/null
+++ b/core/java/android/accounts/AccountAuthenticatorActivity.java
@@ -0,0 +1,102 @@
+/*
+ * 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.accounts;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * Base class for implementing an Activity that is used to help implement an
+ * AbstractAccountAuthenticator. If the AbstractAccountAuthenticator needs to return an Intent
+ * that is to be used to launch an Activity that needs to return results to satisfy an
+ * AbstractAccountAuthenticator request, it should store the AccountAuthenticatorResponse
+ * inside of the Intent as follows:
+ * <p>
+ * intent.putExtra(Constants.ACCOUNT_AUTHENTICATOR_RESPONSE_KEY, response);
+ * <p>
+ * The activity that it launches should extend the AccountAuthenticatorActivity. If this
+ * activity has a result that satisfies the original request it sets it via:
+ * <p>
+ * setAccountAuthenticatorResult(result)
+ * <p>
+ * This result will be sent as the result of the request when the activity finishes. If this
+ * is never set or if it is set to null then the request will be canceled when the activity
+ * finishes.
+ */
+public class AccountAuthenticatorActivity extends Activity {
+ private AccountAuthenticatorResponse mAccountAuthenticatorResponse = null;
+ private Bundle mResultBundle = null;
+
+ /**
+ * Set the result that is to be sent as the result of the request that caused this
+ * Activity to be launched. If result is null or this method is never called then
+ * the request will be canceled.
+ * @param result this is returned as the result of the AbstractAccountAuthenticator request
+ */
+ public final void setAccountAuthenticatorResult(Bundle result) {
+ mResultBundle = result;
+ }
+
+ /**
+ * Retreives the AccountAuthenticatorResponse from either the intent of the icicle, if the
+ * icicle is non-zero.
+ * @param icicle the save instance data of this Activity, may be null
+ */
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ if (icicle == null) {
+ Intent intent = getIntent();
+ mAccountAuthenticatorResponse =
+ intent.getParcelableExtra(Constants.ACCOUNT_AUTHENTICATOR_RESPONSE_KEY);
+ } else {
+ mAccountAuthenticatorResponse =
+ icicle.getParcelable(Constants.ACCOUNT_AUTHENTICATOR_RESPONSE_KEY);
+ }
+
+ if (mAccountAuthenticatorResponse != null) {
+ mAccountAuthenticatorResponse.onRequestContinued();
+ }
+ }
+
+ /**
+ * Saves the AccountAuthenticatorResponse in the instance state.
+ * @param outState where to store any instance data
+ */
+ protected void onSaveInstanceState(Bundle outState) {
+ outState.putParcelable(Constants.ACCOUNT_AUTHENTICATOR_RESPONSE_KEY,
+ mAccountAuthenticatorResponse);
+ super.onSaveInstanceState(outState);
+ }
+
+ /**
+ * Sends the result or a Constants.ERROR_CODE_CANCELED error if a result isn't present.
+ */
+ public void finish() {
+ if (mAccountAuthenticatorResponse != null) {
+ // send the result bundle back if set, otherwise send an error.
+ if (mResultBundle != null) {
+ mAccountAuthenticatorResponse.onResult(mResultBundle);
+ } else {
+ mAccountAuthenticatorResponse.onError(Constants.ERROR_CODE_CANCELED, "canceled");
+ }
+ mAccountAuthenticatorResponse = null;
+ }
+ super.finish();
+ }
+}
diff --git a/core/java/android/accounts/AccountAuthenticatorCache.java b/core/java/android/accounts/AccountAuthenticatorCache.java
new file mode 100644
index 0000000..83aae3a
--- /dev/null
+++ b/core/java/android/accounts/AccountAuthenticatorCache.java
@@ -0,0 +1,73 @@
+/*
+ * 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.accounts;
+
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.RegisteredServicesCache;
+import android.content.res.XmlResourceParser;
+import android.content.res.TypedArray;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+import android.util.AttributeSet;
+import android.util.Xml;
+
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import com.google.android.collect.Maps;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * A cache of services that export the {@link IAccountAuthenticator} interface. This cache
+ * is built by interrogating the {@link PackageManager} and is updated as packages are added,
+ * removed and changed. The authenticators are referred to by their account type and
+ * are made available via the {@link RegisteredServicesCache#getServiceInfo} method.
+ * @hide
+ */
+/* package private */ class AccountAuthenticatorCache extends RegisteredServicesCache<String> {
+ private static final String TAG = "Account";
+
+ private static final String SERVICE_INTERFACE = "android.accounts.AccountAuthenticator";
+ private static final String SERVICE_META_DATA = "android.accounts.AccountAuthenticator";
+ private static final String ATTRIBUTES_NAME = "account-authenticator";
+
+ public AccountAuthenticatorCache(Context context) {
+ super(context, SERVICE_INTERFACE, SERVICE_META_DATA, ATTRIBUTES_NAME);
+ }
+
+ public String parseServiceAttributes(AttributeSet attrs) {
+ TypedArray sa = mContext.getResources().obtainAttributes(attrs,
+ com.android.internal.R.styleable.AccountAuthenticator);
+ try {
+ return sa.getString(com.android.internal.R.styleable.AccountAuthenticator_accountType);
+ } finally {
+ sa.recycle();
+ }
+ }
+}
diff --git a/core/java/android/accounts/AccountAuthenticatorResponse.java b/core/java/android/accounts/AccountAuthenticatorResponse.java
new file mode 100644
index 0000000..7198046
--- /dev/null
+++ b/core/java/android/accounts/AccountAuthenticatorResponse.java
@@ -0,0 +1,82 @@
+/*
+ * 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.accounts;
+
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.os.RemoteException;
+
+/**
+ * Object that wraps calls to an {@link IAccountAuthenticatorResponse} object.
+ * TODO: this interface is still in flux
+ */
+public class AccountAuthenticatorResponse implements Parcelable {
+ private IAccountAuthenticatorResponse mAccountAuthenticatorResponse;
+
+ public AccountAuthenticatorResponse(IAccountAuthenticatorResponse response) {
+ mAccountAuthenticatorResponse = response;
+ }
+
+ public AccountAuthenticatorResponse(Parcel parcel) {
+ mAccountAuthenticatorResponse =
+ IAccountAuthenticatorResponse.Stub.asInterface(parcel.readStrongBinder());
+ }
+
+ public void onResult(Bundle result) {
+ try {
+ mAccountAuthenticatorResponse.onResult(result);
+ } catch (RemoteException e) {
+ // this should never happen
+ }
+ }
+
+ public void onRequestContinued() {
+ try {
+ mAccountAuthenticatorResponse.onRequestContinued();
+ } catch (RemoteException e) {
+ // this should never happen
+ }
+ }
+
+ public void onError(int errorCode, String errorMessage) {
+ try {
+ mAccountAuthenticatorResponse.onError(errorCode, errorMessage);
+ } catch (RemoteException e) {
+ // this should never happen
+ }
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStrongBinder(mAccountAuthenticatorResponse.asBinder());
+ }
+
+ public static final Creator<AccountAuthenticatorResponse> CREATOR =
+ new Creator<AccountAuthenticatorResponse>() {
+ public AccountAuthenticatorResponse createFromParcel(Parcel source) {
+ return new AccountAuthenticatorResponse(source);
+ }
+
+ public AccountAuthenticatorResponse[] newArray(int size) {
+ return new AccountAuthenticatorResponse[size];
+ }
+ };
+}
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
new file mode 100644
index 0000000..4fcaa88
--- /dev/null
+++ b/core/java/android/accounts/AccountManager.java
@@ -0,0 +1,1073 @@
+/*
+ * 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.accounts;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.content.BroadcastReceiver;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.Parcelable;
+import android.util.Config;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.TimeUnit;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.android.collect.Maps;
+
+/**
+ * A class that helps with interactions with the AccountManagerService. It provides
+ * methods to allow for account, password, and authtoken management for all accounts on the
+ * device. Some of these calls are implemented with the help of the corresponding
+ * {@link IAccountAuthenticator} services. One accesses the {@link AccountManager} by calling:
+ * AccountManager accountManager = AccountManager.get(context);
+ *
+ * <p>
+ * TODO(fredq) this interface is still in flux
+ */
+public class AccountManager {
+ private static final String TAG = "AccountManager";
+
+ private final Context mContext;
+ private final IAccountManager mService;
+ private final Handler mMainHandler;
+
+ /**
+ * @hide
+ */
+ public AccountManager(Context context, IAccountManager service) {
+ mContext = context;
+ mService = service;
+ mMainHandler = new Handler(mContext.getMainLooper());
+ }
+
+ /**
+ * @hide used for testing only
+ */
+ public AccountManager(Context context, IAccountManager service, Handler handler) {
+ mContext = context;
+ mService = service;
+ mMainHandler = handler;
+ }
+
+ public static AccountManager get(Context context) {
+ return (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
+ }
+
+ public String blockingGetPassword(Account account) {
+ ensureNotOnMainThread();
+ try {
+ return mService.getPassword(account);
+ } catch (RemoteException e) {
+ // if this happens the entire runtime will restart
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Future1<String> getPassword(final Future1Callback<String> callback,
+ final Account account, final Handler handler) {
+ return startAsFuture(callback, handler, new Callable<String>() {
+ public String call() throws Exception {
+ return blockingGetPassword(account);
+ }
+ });
+ }
+
+ public String blockingGetUserData(Account account, String key) {
+ ensureNotOnMainThread();
+ try {
+ return mService.getUserData(account, key);
+ } catch (RemoteException e) {
+ // if this happens the entire runtime will restart
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Future1<String> getUserData(Future1Callback<String> callback,
+ final Account account, final String key, Handler handler) {
+ return startAsFuture(callback, handler, new Callable<String>() {
+ public String call() throws Exception {
+ return blockingGetUserData(account, key);
+ }
+ });
+ }
+
+ public String[] blockingGetAuthenticatorTypes() {
+ ensureNotOnMainThread();
+ try {
+ return mService.getAuthenticatorTypes();
+ } catch (RemoteException e) {
+ // if this happens the entire runtime will restart
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Future1<String[]> getAuthenticatorTypes(Future1Callback<String[]> callback,
+ Handler handler) {
+ return startAsFuture(callback, handler, new Callable<String[]>() {
+ public String[] call() throws Exception {
+ return blockingGetAuthenticatorTypes();
+ }
+ });
+ }
+
+ public Account[] blockingGetAccounts() {
+ ensureNotOnMainThread();
+ try {
+ return mService.getAccounts();
+ } catch (RemoteException e) {
+ // if this happens the entire runtime will restart
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Account[] blockingGetAccountsByType(String accountType) {
+ ensureNotOnMainThread();
+ try {
+ return mService.getAccountsByType(accountType);
+ } catch (RemoteException e) {
+ // if this happens the entire runtime will restart
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Future1<Account[]> getAccounts(Future1Callback<Account[]> callback, Handler handler) {
+ return startAsFuture(callback, handler, new Callable<Account[]>() {
+ public Account[] call() throws Exception {
+ return blockingGetAccounts();
+ }
+ });
+ }
+
+ public Future1<Account[]> getAccountsByType(Future1Callback<Account[]> callback,
+ final String type, Handler handler) {
+ return startAsFuture(callback, handler, new Callable<Account[]>() {
+ public Account[] call() throws Exception {
+ return blockingGetAccountsByType(type);
+ }
+ });
+ }
+
+ public boolean blockingAddAccountExplicitly(Account account, String password, Bundle extras) {
+ ensureNotOnMainThread();
+ try {
+ return mService.addAccount(account, password, extras);
+ } catch (RemoteException e) {
+ // if this happens the entire runtime will restart
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Future1<Boolean> addAccountExplicitly(final Future1Callback<Boolean> callback,
+ final Account account, final String password, final Bundle extras,
+ final Handler handler) {
+ return startAsFuture(callback, handler, new Callable<Boolean>() {
+ public Boolean call() throws Exception {
+ return blockingAddAccountExplicitly(account, password, extras);
+ }
+ });
+ }
+
+ public void blockingRemoveAccount(Account account) {
+ ensureNotOnMainThread();
+ try {
+ mService.removeAccount(account);
+ } catch (RemoteException e) {
+ // if this happens the entire runtime will restart
+ }
+ }
+
+ public Future1<Void> removeAccount(Future1Callback<Void> callback, final Account account,
+ final Handler handler) {
+ return startAsFuture(callback, handler, new Callable<Void>() {
+ public Void call() throws Exception {
+ blockingRemoveAccount(account);
+ return null;
+ }
+ });
+ }
+
+ public void blockingInvalidateAuthToken(String accountType, String authToken) {
+ ensureNotOnMainThread();
+ try {
+ mService.invalidateAuthToken(accountType, authToken);
+ } catch (RemoteException e) {
+ // if this happens the entire runtime will restart
+ }
+ }
+
+ public Future1<Void> invalidateAuthToken(Future1Callback<Void> callback,
+ final String accountType, final String authToken, final Handler handler) {
+ return startAsFuture(callback, handler, new Callable<Void>() {
+ public Void call() throws Exception {
+ blockingInvalidateAuthToken(accountType, authToken);
+ return null;
+ }
+ });
+ }
+
+ public String blockingPeekAuthToken(Account account, String authTokenType) {
+ ensureNotOnMainThread();
+ try {
+ return mService.peekAuthToken(account, authTokenType);
+ } catch (RemoteException e) {
+ // if this happens the entire runtime will restart
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Future1<String> peekAuthToken(Future1Callback<String> callback,
+ final Account account, final String authTokenType, final Handler handler) {
+ return startAsFuture(callback, handler, new Callable<String>() {
+ public String call() throws Exception {
+ return blockingPeekAuthToken(account, authTokenType);
+ }
+ });
+ }
+
+ public void blockingSetPassword(Account account, String password) {
+ ensureNotOnMainThread();
+ try {
+ mService.setPassword(account, password);
+ } catch (RemoteException e) {
+ // if this happens the entire runtime will restart
+ }
+ }
+
+ public Future1<Void> setPassword(Future1Callback<Void> callback,
+ final Account account, final String password, final Handler handler) {
+ return startAsFuture(callback, handler, new Callable<Void>() {
+ public Void call() throws Exception {
+ blockingSetPassword(account, password);
+ return null;
+ }
+ });
+ }
+
+ public void blockingClearPassword(Account account) {
+ ensureNotOnMainThread();
+ try {
+ mService.clearPassword(account);
+ } catch (RemoteException e) {
+ // if this happens the entire runtime will restart
+ }
+ }
+
+ public Future1<Void> clearPassword(final Future1Callback<Void> callback, final Account account,
+ final Handler handler) {
+ return startAsFuture(callback, handler, new Callable<Void>() {
+ public Void call() throws Exception {
+ blockingClearPassword(account);
+ return null;
+ }
+ });
+ }
+
+ public void blockingSetUserData(Account account, String key, String value) {
+ ensureNotOnMainThread();
+ try {
+ mService.setUserData(account, key, value);
+ } catch (RemoteException e) {
+ // if this happens the entire runtime will restart
+ }
+ }
+
+ public Future1<Void> setUserData(Future1Callback<Void> callback,
+ final Account account, final String key, final String value, final Handler handler) {
+ return startAsFuture(callback, handler, new Callable<Void>() {
+ public Void call() throws Exception {
+ blockingSetUserData(account, key, value);
+ return null;
+ }
+ });
+ }
+
+ public void blockingSetAuthToken(Account account, String authTokenType, String authToken) {
+ ensureNotOnMainThread();
+ try {
+ mService.setAuthToken(account, authTokenType, authToken);
+ } catch (RemoteException e) {
+ // if this happens the entire runtime will restart
+ }
+ }
+
+ public Future1<Void> setAuthToken(Future1Callback<Void> callback,
+ final Account account, final String authTokenType, final String authToken,
+ final Handler handler) {
+ return startAsFuture(callback, handler, new Callable<Void>() {
+ public Void call() throws Exception {
+ blockingSetAuthToken(account, authTokenType, authToken);
+ return null;
+ }
+ });
+ }
+
+ public String blockingGetAuthToken(Account account, String authTokenType,
+ boolean notifyAuthFailure)
+ throws OperationCanceledException, IOException, AuthenticatorException {
+ ensureNotOnMainThread();
+ Bundle bundle = getAuthToken(account, authTokenType, notifyAuthFailure, null /* callback */,
+ null /* handler */).getResult();
+ return bundle.getString(Constants.AUTHTOKEN_KEY);
+ }
+
+ /**
+ * Request the auth token for this account/authTokenType. If this succeeds then the
+ * auth token will then be passed to the activity. If this results in an authentication
+ * failure then a login intent will be returned that can be invoked to prompt the user to
+ * update their credentials. This login activity will return the auth token to the calling
+ * activity. If activity is null then the login intent will not be invoked.
+ *
+ * @param account the account whose auth token should be retrieved
+ * @param authTokenType the auth token type that should be retrieved
+ * @param loginOptions
+ * @param activity the activity to launch the login intent, if necessary, and to which
+ */
+ public Future2 getAuthToken(
+ final Account account, final String authTokenType, final Bundle loginOptions,
+ final Activity activity, Future2Callback callback, Handler handler) {
+ if (activity == null) throw new IllegalArgumentException("activity is null");
+ if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
+ return new AmsTask(activity, handler, callback) {
+ public void doWork() throws RemoteException {
+ mService.getAuthToken(mResponse, account, authTokenType,
+ false /* notifyOnAuthFailure */, true /* expectActivityLaunch */,
+ loginOptions);
+ }
+ }.start();
+ }
+
+ public Future2 getAuthToken(
+ final Account account, final String authTokenType, final boolean notifyAuthFailure,
+ Future2Callback callback, Handler handler) {
+ if (account == null) throw new IllegalArgumentException("account is null");
+ if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
+ return new AmsTask(null, handler, callback) {
+ public void doWork() throws RemoteException {
+ mService.getAuthToken(mResponse, account, authTokenType,
+ notifyAuthFailure, false /* expectActivityLaunch */, null /* options */);
+ }
+ }.start();
+ }
+
+ public Future2 addAccount(final String accountType,
+ final String authTokenType, final String[] requiredFeatures,
+ final Bundle addAccountOptions,
+ final Activity activity, Future2Callback callback, Handler handler) {
+ return new AmsTask(activity, handler, callback) {
+ public void doWork() throws RemoteException {
+ mService.addAcount(mResponse, accountType, authTokenType,
+ requiredFeatures, activity != null, addAccountOptions);
+ }
+ }.start();
+ }
+
+ /** @deprecated use {@link #confirmCredentials} instead */
+ public Future1<Boolean> confirmPassword(final Account account, final String password,
+ Future1Callback<Boolean> callback, Handler handler) {
+ return new AMSTaskBoolean(handler, callback) {
+ public void doWork() throws RemoteException {
+ mService.confirmPassword(response, account, password);
+ }
+ };
+ }
+
+ public Account[] blockingGetAccountsWithTypeAndFeatures(String type, String[] features)
+ throws AuthenticatorException, IOException, OperationCanceledException {
+ Future2 future = getAccountsWithTypeAndFeatures(type, features,
+ null /* callback */, null /* handler */);
+ Bundle result = future.getResult();
+ Parcelable[] accountsTemp = result.getParcelableArray(Constants.ACCOUNTS_KEY);
+ if (accountsTemp == null) {
+ throw new AuthenticatorException("accounts should not be null");
+ }
+ Account[] accounts = new Account[accountsTemp.length];
+ for (int i = 0; i < accountsTemp.length; i++) {
+ accounts[i] = (Account) accountsTemp[i];
+ }
+ return accounts;
+ }
+
+ public Future2 getAccountsWithTypeAndFeatures(
+ final String type, final String[] features,
+ Future2Callback callback, Handler handler) {
+ if (type == null) throw new IllegalArgumentException("type is null");
+ return new AmsTask(null /* activity */, handler, callback) {
+ public void doWork() throws RemoteException {
+ mService.getAccountsByTypeAndFeatures(mResponse, type, features);
+ }
+ }.start();
+ }
+
+ public Future2 confirmCredentials(final Account account, final Activity activity,
+ final Future2Callback callback,
+ final Handler handler) {
+ return new AmsTask(activity, handler, callback) {
+ public void doWork() throws RemoteException {
+ mService.confirmCredentials(mResponse, account, activity != null);
+ }
+ }.start();
+ }
+
+ public Future2 updateCredentials(final Account account, final String authTokenType,
+ final Bundle loginOptions, final Activity activity,
+ final Future2Callback callback,
+ final Handler handler) {
+ return new AmsTask(activity, handler, callback) {
+ public void doWork() throws RemoteException {
+ mService.updateCredentials(mResponse, account, authTokenType, activity != null,
+ loginOptions);
+ }
+ }.start();
+ }
+
+ public Future2 editProperties(final String accountType, final Activity activity,
+ final Future2Callback callback,
+ final Handler handler) {
+ return new AmsTask(activity, handler, callback) {
+ public void doWork() throws RemoteException {
+ mService.editProperties(mResponse, accountType, activity != null);
+ }
+ }.start();
+ }
+
+ private void ensureNotOnMainThread() {
+ final Looper looper = Looper.myLooper();
+ if (looper != null && looper == mContext.getMainLooper()) {
+ // We really want to throw an exception here, but GTalkService exercises this
+ // path quite a bit and needs some serious rewrite in order to work properly.
+ //noinspection ThrowableInstanceNeverThrow
+// Log.e(TAG, "calling this from your main thread can lead to deadlock and/or ANRs",
+// new Exception());
+ // TODO(fredq) remove the log and throw this exception when the callers are fixed
+// throw new IllegalStateException(
+// "calling this from your main thread can lead to deadlock");
+ }
+ }
+
+ private void postToHandler(Handler handler, final Future2Callback callback,
+ final Future2 future) {
+ handler = handler == null ? mMainHandler : handler;
+ handler.post(new Runnable() {
+ public void run() {
+ callback.run(future);
+ }
+ });
+ }
+
+ private void postToHandler(Handler handler, final OnAccountsUpdatedListener listener,
+ final Account[] accounts) {
+ handler = handler == null ? mMainHandler : handler;
+ handler.post(new Runnable() {
+ public void run() {
+ listener.onAccountsUpdated(accounts);
+ }
+ });
+ }
+
+ private <V> void postToHandler(Handler handler, final Future1Callback<V> callback,
+ final Future1<V> future) {
+ handler = handler == null ? mMainHandler : handler;
+ handler.post(new Runnable() {
+ public void run() {
+ callback.run(future);
+ }
+ });
+ }
+
+ private <V> Future1<V> startAsFuture(Future1Callback<V> callback, Handler handler,
+ Callable<V> callable) {
+ final FutureTaskWithCallback<V> task =
+ new FutureTaskWithCallback<V>(callback, callable, handler);
+ new Thread(task).start();
+ return task;
+ }
+
+ private class FutureTaskWithCallback<V> extends FutureTask<V> implements Future1<V> {
+ final Future1Callback<V> mCallback;
+ final Handler mHandler;
+
+ public FutureTaskWithCallback(Future1Callback<V> callback, Callable<V> callable,
+ Handler handler) {
+ super(callable);
+ mCallback = callback;
+ mHandler = handler;
+ }
+
+ protected void done() {
+ if (mCallback != null) {
+ postToHandler(mHandler, mCallback, this);
+ }
+ }
+
+ public V internalGetResult(Long timeout, TimeUnit unit) throws OperationCanceledException {
+ try {
+ if (timeout == null) {
+ return get();
+ } else {
+ return get(timeout, unit);
+ }
+ } catch (InterruptedException e) {
+ // we will cancel the task below
+ } catch (CancellationException e) {
+ // we will cancel the task below
+ } catch (TimeoutException e) {
+ // we will cancel the task below
+ } catch (ExecutionException e) {
+ // this should never happen
+ throw new IllegalStateException(e.getCause());
+ } finally {
+ cancel(true /* interruptIfRunning */);
+ }
+ throw new OperationCanceledException();
+ }
+
+ public V getResult() throws OperationCanceledException {
+ return internalGetResult(null, null);
+ }
+
+ public V getResult(long timeout, TimeUnit unit) throws OperationCanceledException {
+ return internalGetResult(null, null);
+ }
+ }
+
+ private abstract class AmsTask extends FutureTask<Bundle> implements Future2 {
+ final IAccountManagerResponse mResponse;
+ final Handler mHandler;
+ final Future2Callback mCallback;
+ final Activity mActivity;
+ final Thread mThread;
+ public AmsTask(Activity activity, Handler handler, Future2Callback callback) {
+ super(new Callable<Bundle>() {
+ public Bundle call() throws Exception {
+ throw new IllegalStateException("this should never be called");
+ }
+ });
+
+ mHandler = handler;
+ mCallback = callback;
+ mActivity = activity;
+ mResponse = new Response();
+ mThread = new Thread(new Runnable() {
+ public void run() {
+ try {
+ doWork();
+ } catch (RemoteException e) {
+ // never happens
+ }
+ }
+ }, "AmsTask");
+ }
+
+ public final Future2 start() {
+ mThread.start();
+ return this;
+ }
+
+ public abstract void doWork() throws RemoteException;
+
+ private Bundle internalGetResult(Long timeout, TimeUnit unit)
+ throws OperationCanceledException, IOException, AuthenticatorException {
+ try {
+ if (timeout == null) {
+ return get();
+ } else {
+ return get(timeout, unit);
+ }
+ } catch (CancellationException e) {
+ throw new OperationCanceledException();
+ } catch (TimeoutException e) {
+ // fall through and cancel
+ } catch (InterruptedException e) {
+ // fall through and cancel
+ } catch (ExecutionException e) {
+ final Throwable cause = e.getCause();
+ if (cause instanceof IOException) {
+ throw (IOException) cause;
+ } else if (cause instanceof UnsupportedOperationException) {
+ throw new AuthenticatorException(cause);
+ } else if (cause instanceof AuthenticatorException) {
+ throw (AuthenticatorException) cause;
+ } else if (cause instanceof RuntimeException) {
+ throw (RuntimeException) cause;
+ } else if (cause instanceof Error) {
+ throw (Error) cause;
+ } else {
+ throw new IllegalStateException(cause);
+ }
+ } finally {
+ cancel(true /* interrupt if running */);
+ }
+ throw new OperationCanceledException();
+ }
+
+ public Bundle getResult()
+ throws OperationCanceledException, IOException, AuthenticatorException {
+ return internalGetResult(null, null);
+ }
+
+ public Bundle getResult(long timeout, TimeUnit unit)
+ throws OperationCanceledException, IOException, AuthenticatorException {
+ return internalGetResult(timeout, unit);
+ }
+
+ protected void done() {
+ if (mCallback != null) {
+ postToHandler(mHandler, mCallback, this);
+ }
+ }
+
+ /** Handles the responses from the AccountManager */
+ private class Response extends IAccountManagerResponse.Stub {
+ public void onResult(Bundle bundle) {
+ Intent intent = bundle.getParcelable("intent");
+ if (intent != null && mActivity != null) {
+ // since the user provided an Activity we will silently start intents
+ // that we see
+ mActivity.startActivity(intent);
+ // leave the Future running to wait for the real response to this request
+ } else {
+ set(bundle);
+ }
+ }
+
+ public void onError(int code, String message) {
+ if (code == Constants.ERROR_CODE_CANCELED) {
+ // the authenticator indicated that this request was canceled, do so now
+ cancel(true /* mayInterruptIfRunning */);
+ return;
+ }
+ setException(convertErrorToException(code, message));
+ }
+ }
+
+ }
+
+ private abstract class AMSTaskBoolean extends FutureTask<Boolean> implements Future1<Boolean> {
+ final IAccountManagerResponse response;
+ final Handler mHandler;
+ final Future1Callback<Boolean> mCallback;
+ public AMSTaskBoolean(Handler handler, Future1Callback<Boolean> callback) {
+ super(new Callable<Boolean>() {
+ public Boolean call() throws Exception {
+ throw new IllegalStateException("this should never be called");
+ }
+ });
+
+ mHandler = handler;
+ mCallback = callback;
+ response = new Response();
+
+ new Thread(new Runnable() {
+ public void run() {
+ try {
+ doWork();
+ } catch (RemoteException e) {
+ // never happens
+ }
+ }
+ }).start();
+ }
+
+ public abstract void doWork() throws RemoteException;
+
+
+ protected void done() {
+ if (mCallback != null) {
+ postToHandler(mHandler, mCallback, this);
+ }
+ }
+
+ private Boolean internalGetResult(Long timeout, TimeUnit unit) {
+ try {
+ if (timeout == null) {
+ return get();
+ } else {
+ return get(timeout, unit);
+ }
+ } catch (InterruptedException e) {
+ // fall through and cancel
+ } catch (TimeoutException e) {
+ // fall through and cancel
+ } catch (CancellationException e) {
+ return false;
+ } catch (ExecutionException e) {
+ final Throwable cause = e.getCause();
+ if (cause instanceof IOException) {
+ return false;
+ } else if (cause instanceof UnsupportedOperationException) {
+ return false;
+ } else if (cause instanceof AuthenticatorException) {
+ return false;
+ } else if (cause instanceof RuntimeException) {
+ throw (RuntimeException) cause;
+ } else if (cause instanceof Error) {
+ throw (Error) cause;
+ } else {
+ throw new IllegalStateException(cause);
+ }
+ } finally {
+ cancel(true /* interrupt if running */);
+ }
+ return false;
+ }
+
+ public Boolean getResult() throws OperationCanceledException {
+ return internalGetResult(null, null);
+ }
+
+ public Boolean getResult(long timeout, TimeUnit unit) throws OperationCanceledException {
+ return internalGetResult(timeout, unit);
+ }
+
+ private class Response extends IAccountManagerResponse.Stub {
+ public void onResult(Bundle bundle) {
+ try {
+ if (bundle.containsKey(Constants.BOOLEAN_RESULT_KEY)) {
+ set(bundle.getBoolean(Constants.BOOLEAN_RESULT_KEY));
+ return;
+ }
+ } catch (ClassCastException e) {
+ // we will set the exception below
+ }
+ onError(Constants.ERROR_CODE_INVALID_RESPONSE, "no result in response");
+ }
+
+ public void onError(int code, String message) {
+ if (code == Constants.ERROR_CODE_CANCELED) {
+ cancel(true /* mayInterruptIfRunning */);
+ return;
+ }
+ setException(convertErrorToException(code, message));
+ }
+ }
+
+ }
+
+ private Exception convertErrorToException(int code, String message) {
+ if (code == Constants.ERROR_CODE_NETWORK_ERROR) {
+ return new IOException(message);
+ }
+
+ if (code == Constants.ERROR_CODE_UNSUPPORTED_OPERATION) {
+ return new UnsupportedOperationException(message);
+ }
+
+ if (code == Constants.ERROR_CODE_INVALID_RESPONSE) {
+ return new AuthenticatorException(message);
+ }
+
+ if (code == Constants.ERROR_CODE_BAD_ARGUMENTS) {
+ return new IllegalArgumentException(message);
+ }
+
+ return new AuthenticatorException(message);
+ }
+
+ private class GetAuthTokenByTypeAndFeaturesTask extends AmsTask implements Future2Callback {
+ GetAuthTokenByTypeAndFeaturesTask(final String accountType, final String authTokenType,
+ final String[] features, Activity activityForPrompting,
+ final Bundle addAccountOptions, final Bundle loginOptions,
+ Future2Callback callback, Handler handler) {
+ super(activityForPrompting, handler, callback);
+ if (accountType == null) throw new IllegalArgumentException("account type is null");
+ mAccountType = accountType;
+ mAuthTokenType = authTokenType;
+ mFeatures = features;
+ mAddAccountOptions = addAccountOptions;
+ mLoginOptions = loginOptions;
+ mMyCallback = this;
+ }
+ volatile Future2 mFuture = null;
+ final String mAccountType;
+ final String mAuthTokenType;
+ final String[] mFeatures;
+ final Bundle mAddAccountOptions;
+ final Bundle mLoginOptions;
+ final Future2Callback mMyCallback;
+
+ public void doWork() throws RemoteException {
+ getAccountsWithTypeAndFeatures(mAccountType, mFeatures, new Future2Callback() {
+ public void run(Future2 future) {
+ Bundle getAccountsResult;
+ try {
+ getAccountsResult = future.getResult();
+ } catch (OperationCanceledException e) {
+ setException(e);
+ return;
+ } catch (IOException e) {
+ setException(e);
+ return;
+ } catch (AuthenticatorException e) {
+ setException(e);
+ return;
+ }
+
+ Parcelable[] accounts =
+ getAccountsResult.getParcelableArray(Constants.ACCOUNTS_KEY);
+ if (accounts.length == 0) {
+ if (mActivity != null) {
+ // no accounts, add one now. pretend that the user directly
+ // made this request
+ mFuture = addAccount(mAccountType, mAuthTokenType, mFeatures,
+ mAddAccountOptions, mActivity, mMyCallback, mHandler);
+ } else {
+ // send result since we can't prompt to add an account
+ Bundle result = new Bundle();
+ result.putString(Constants.ACCOUNT_NAME_KEY, null);
+ result.putString(Constants.ACCOUNT_TYPE_KEY, null);
+ result.putString(Constants.AUTHTOKEN_KEY, null);
+ try {
+ mResponse.onResult(result);
+ } catch (RemoteException e) {
+ // this will never happen
+ }
+ // we are done
+ }
+ } else if (accounts.length == 1) {
+ // have a single account, return an authtoken for it
+ if (mActivity == null) {
+ mFuture = getAuthToken((Account) accounts[0], mAuthTokenType,
+ false /* notifyAuthFailure */, mMyCallback, mHandler);
+ } else {
+ mFuture = getAuthToken((Account) accounts[0],
+ mAuthTokenType, mLoginOptions,
+ mActivity, mMyCallback, mHandler);
+ }
+ } else {
+ if (mActivity != null) {
+ IAccountManagerResponse chooseResponse =
+ new IAccountManagerResponse.Stub() {
+ public void onResult(Bundle value) throws RemoteException {
+ Account account = new Account(
+ value.getString(Constants.ACCOUNT_NAME_KEY),
+ value.getString(Constants.ACCOUNT_TYPE_KEY));
+ mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions,
+ mActivity, mMyCallback, mHandler);
+ }
+
+ public void onError(int errorCode, String errorMessage)
+ throws RemoteException {
+ mResponse.onError(errorCode, errorMessage);
+ }
+ };
+ // have many accounts, launch the chooser
+ Intent intent = new Intent();
+ intent.setClassName("android",
+ "android.accounts.ChooseAccountActivity");
+ intent.putExtra(Constants.ACCOUNTS_KEY, accounts);
+ intent.putExtra(Constants.ACCOUNT_MANAGER_RESPONSE_KEY,
+ new AccountManagerResponse(chooseResponse));
+ mActivity.startActivity(intent);
+ // the result will arrive via the IAccountManagerResponse
+ } else {
+ // send result since we can't prompt to select an account
+ Bundle result = new Bundle();
+ result.putString(Constants.ACCOUNTS_KEY, null);
+ try {
+ mResponse.onResult(result);
+ } catch (RemoteException e) {
+ // this will never happen
+ }
+ // we are done
+ }
+ }
+ }}, mHandler);
+ }
+
+
+
+ // TODO(fredq) pass through the calls to our implemention of Future2 to the underlying
+ // future that we create. We need to do things like have cancel cancel the mFuture, if set
+ // or to cause this to be canceled if mFuture isn't set.
+ // Once this is done then getAuthTokenByFeatures can be changed to return a Future2.
+
+ public void run(Future2 future) {
+ try {
+ set(future.get());
+ } catch (InterruptedException e) {
+ cancel(true);
+ } catch (CancellationException e) {
+ cancel(true);
+ } catch (ExecutionException e) {
+ setException(e.getCause());
+ }
+ }
+ }
+
+ public void getAuthTokenByFeatures(
+ final String accountType, final String authTokenType, final String[] features,
+ final Activity activityForPrompting, final Bundle addAccountOptions,
+ final Bundle loginOptions,
+ final Future2Callback callback, final Handler handler) {
+ if (accountType == null) throw new IllegalArgumentException("account type is null");
+ if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
+ new GetAuthTokenByTypeAndFeaturesTask(accountType, authTokenType, features,
+ activityForPrompting, addAccountOptions, loginOptions, callback, handler).start();
+ }
+
+ private final HashMap<OnAccountsUpdatedListener, Handler> mAccountsUpdatedListeners =
+ Maps.newHashMap();
+
+ // These variable are only used from the LOGIN_ACCOUNTS_CHANGED_ACTION BroadcastReceiver
+ // and its getAccounts() callback which are both invoked only on the main thread. As a
+ // result we don't need to protect against concurrent accesses and any changes are guaranteed
+ // to be visible when used. Basically, these two variables are thread-confined.
+ private Future1<Account[]> mAccountsLookupFuture = null;
+ private boolean mAccountLookupPending = false;
+
+ /**
+ * BroadcastReceiver that listens for the LOGIN_ACCOUNTS_CHANGED_ACTION intent
+ * so that it can read the updated list of accounts and send them to the listener
+ * in mAccountsUpdatedListeners.
+ */
+ private final BroadcastReceiver mAccountsChangedBroadcastReceiver = new BroadcastReceiver() {
+ public void onReceive(final Context context, final Intent intent) {
+ if (mAccountsLookupFuture != null) {
+ // an accounts lookup is already in progress,
+ // don't bother starting another request
+ mAccountLookupPending = true;
+ return;
+ }
+ // initiate a read of the accounts
+ mAccountsLookupFuture = getAccounts(new Future1Callback<Account[]>() {
+ public void run(Future1<Account[]> future) {
+ // clear the future so that future receives will try the lookup again
+ mAccountsLookupFuture = null;
+
+ // get the accounts array
+ Account[] accounts;
+ try {
+ accounts = future.getResult();
+ } catch (OperationCanceledException e) {
+ // this should never happen, but if it does pretend we got another
+ // accounts changed broadcast
+ if (Config.LOGD) {
+ Log.d(TAG, "the accounts lookup for listener notifications was "
+ + "canceled, try again by simulating the receipt of "
+ + "a LOGIN_ACCOUNTS_CHANGED_ACTION broadcast");
+ }
+ onReceive(context, intent);
+ return;
+ }
+
+ // send the result to the listeners
+ synchronized (mAccountsUpdatedListeners) {
+ for (Map.Entry<OnAccountsUpdatedListener, Handler> entry :
+ mAccountsUpdatedListeners.entrySet()) {
+ Account[] accountsCopy = new Account[accounts.length];
+ // send the listeners a copy to make sure that one doesn't
+ // change what another sees
+ System.arraycopy(accounts, 0, accountsCopy, 0, accountsCopy.length);
+ postToHandler(entry.getValue(), entry.getKey(), accountsCopy);
+ }
+ }
+
+ // If mAccountLookupPending was set when the account lookup finished it
+ // means that we had previously ignored a LOGIN_ACCOUNTS_CHANGED_ACTION
+ // intent because a lookup was already in progress. Now that we are done
+ // with this lookup and notification pretend that another intent
+ // was received by calling onReceive() directly.
+ if (mAccountLookupPending) {
+ mAccountLookupPending = false;
+ onReceive(context, intent);
+ return;
+ }
+ }
+ }, mMainHandler);
+ }
+ };
+
+ /**
+ * Add a {@link OnAccountsUpdatedListener} to this instance of the {@link AccountManager}.
+ * The listener is guaranteed to be invoked on the thread of the Handler that is passed
+ * in or the main thread's Handler if handler is null.
+ * @param listener the listener to add
+ * @param handler the Handler whose thread will be used to invoke the listener. If null
+ * the AccountManager context's main thread will be used.
+ * @param updateImmediately if true then the listener will be invoked as a result of this
+ * call.
+ * @throws IllegalArgumentException if listener is null
+ * @throws IllegalStateException if listener was already added
+ */
+ public void addOnAccountsUpdatedListener(final OnAccountsUpdatedListener listener,
+ Handler handler, boolean updateImmediately) {
+ if (listener == null) {
+ throw new IllegalArgumentException("the listener is null");
+ }
+ synchronized (mAccountsUpdatedListeners) {
+ if (mAccountsUpdatedListeners.containsKey(listener)) {
+ throw new IllegalStateException("this listener is already added");
+ }
+ final boolean wasEmpty = mAccountsUpdatedListeners.isEmpty();
+
+ mAccountsUpdatedListeners.put(listener, handler);
+
+ if (wasEmpty) {
+ // Register a broadcast receiver to monitor account changes
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Constants.LOGIN_ACCOUNTS_CHANGED_ACTION);
+ mContext.registerReceiver(mAccountsChangedBroadcastReceiver, intentFilter);
+ }
+ }
+
+ if (updateImmediately) {
+ getAccounts(new Future1Callback<Account[]>() {
+ public void run(Future1<Account[]> future) {
+ try {
+ listener.onAccountsUpdated(future.getResult());
+ } catch (OperationCanceledException e) {
+ // ignore
+ }
+ }
+ }, handler);
+ }
+ }
+
+ /**
+ * Remove an {@link OnAccountsUpdatedListener} that was previously registered with
+ * {@link #addOnAccountsUpdatedListener}.
+ * @param listener the listener to remove
+ * @throws IllegalArgumentException if listener is null
+ * @throws IllegalStateException if listener was not already added
+ */
+ public void removeOnAccountsUpdatedListener(OnAccountsUpdatedListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("the listener is null");
+ }
+ synchronized (mAccountsUpdatedListeners) {
+ if (mAccountsUpdatedListeners.remove(listener) == null) {
+ throw new IllegalStateException("this listener was not previously added");
+ }
+ if (mAccountsUpdatedListeners.isEmpty()) {
+ mContext.unregisterReceiver(mAccountsChangedBroadcastReceiver);
+ }
+ }
+ }
+}
diff --git a/core/java/android/accounts/AccountManagerResponse.java b/core/java/android/accounts/AccountManagerResponse.java
new file mode 100644
index 0000000..25371fd
--- /dev/null
+++ b/core/java/android/accounts/AccountManagerResponse.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 android.accounts;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+/**
+ * Object that wraps calls to an {@link android.accounts.IAccountManagerResponse} object.
+ * @hide
+ */
+public class AccountManagerResponse implements Parcelable {
+ private IAccountManagerResponse mResponse;
+
+ public AccountManagerResponse(IAccountManagerResponse response) {
+ mResponse = response;
+ }
+
+ public AccountManagerResponse(Parcel parcel) {
+ mResponse =
+ IAccountManagerResponse.Stub.asInterface(parcel.readStrongBinder());
+ }
+
+ public void onResult(Bundle result) {
+ try {
+ mResponse.onResult(result);
+ } catch (RemoteException e) {
+ // this should never happen
+ }
+ }
+
+ public void onError(int errorCode, String errorMessage) {
+ try {
+ mResponse.onError(errorCode, errorMessage);
+ } catch (RemoteException e) {
+ // this should never happen
+ }
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStrongBinder(mResponse.asBinder());
+ }
+
+ public static final Creator<AccountManagerResponse> CREATOR =
+ new Creator<AccountManagerResponse>() {
+ public AccountManagerResponse createFromParcel(Parcel source) {
+ return new AccountManagerResponse(source);
+ }
+
+ public AccountManagerResponse[] newArray(int size) {
+ return new AccountManagerResponse[size];
+ }
+ };
+} \ No newline at end of file
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
new file mode 100644
index 0000000..545241f
--- /dev/null
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -0,0 +1,1185 @@
+/*
+ * 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.accounts;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.app.PendingIntent;
+import android.app.NotificationManager;
+import android.app.Notification;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.R;
+
+/**
+ * A system service that provides account, password, and authtoken management for all
+ * accounts on the device. Some of these calls are implemented with the help of the corresponding
+ * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
+ * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
+ * AccountManager accountManager =
+ * (AccountManager)context.getSystemService(Context.ACCOUNT_SERVICE)
+ * @hide
+ */
+public class AccountManagerService extends IAccountManager.Stub {
+ private static final String TAG = "AccountManagerService";
+
+ private static final int TIMEOUT_DELAY_MS = 1000 * 60;
+ private static final String DATABASE_NAME = "accounts.db";
+ private static final int DATABASE_VERSION = 2;
+
+ private final Context mContext;
+
+ private HandlerThread mMessageThread;
+ private final MessageHandler mMessageHandler;
+
+ // Messages that can be sent on mHandler
+ private static final int MESSAGE_TIMED_OUT = 3;
+ private static final int MESSAGE_CONNECTED = 7;
+ private static final int MESSAGE_DISCONNECTED = 8;
+
+ private final AccountAuthenticatorCache mAuthenticatorCache;
+ private final AuthenticatorBindHelper mBindHelper;
+ private final DatabaseHelper mOpenHelper;
+ private final SimWatcher mSimWatcher;
+
+ private static final String TABLE_ACCOUNTS = "accounts";
+ private static final String ACCOUNTS_ID = "_id";
+ private static final String ACCOUNTS_NAME = "name";
+ private static final String ACCOUNTS_TYPE = "type";
+ private static final String ACCOUNTS_PASSWORD = "password";
+
+ private static final String TABLE_AUTHTOKENS = "authtokens";
+ private static final String AUTHTOKENS_ID = "_id";
+ private static final String AUTHTOKENS_ACCOUNTS_ID = "accounts_id";
+ private static final String AUTHTOKENS_TYPE = "type";
+ private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
+
+ private static final String TABLE_EXTRAS = "extras";
+ private static final String EXTRAS_ID = "_id";
+ private static final String EXTRAS_ACCOUNTS_ID = "accounts_id";
+ private static final String EXTRAS_KEY = "key";
+ private static final String EXTRAS_VALUE = "value";
+
+ private static final String TABLE_META = "meta";
+ private static final String META_KEY = "key";
+ private static final String META_VALUE = "value";
+
+ private static final String[] ACCOUNT_NAME_TYPE_PROJECTION =
+ new String[]{ACCOUNTS_ID, ACCOUNTS_NAME, ACCOUNTS_TYPE};
+ private static final Intent ACCOUNTS_CHANGED_INTENT =
+ new Intent(Constants.LOGIN_ACCOUNTS_CHANGED_ACTION);
+
+ private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
+ private static final int NOTIFICATION_ID = 234;
+
+ public class AuthTokenKey {
+ public final Account mAccount;
+ public final String mAuthTokenType;
+ private final int mHashCode;
+
+ public AuthTokenKey(Account account, String authTokenType) {
+ mAccount = account;
+ mAuthTokenType = authTokenType;
+ mHashCode = computeHashCode();
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof AuthTokenKey)) {
+ return false;
+ }
+ AuthTokenKey other = (AuthTokenKey)o;
+ if (!mAccount.equals(other.mAccount)) {
+ return false;
+ }
+ return (mAuthTokenType == null)
+ ? other.mAuthTokenType == null
+ : mAuthTokenType.equals(other.mAuthTokenType);
+ }
+
+ private int computeHashCode() {
+ int result = 17;
+ result = 31 * result + mAccount.hashCode();
+ result = 31 * result + ((mAuthTokenType == null) ? 0 : mAuthTokenType.hashCode());
+ return result;
+ }
+
+ public int hashCode() {
+ return mHashCode;
+ }
+ }
+
+ public AccountManagerService(Context context) {
+ mContext = context;
+
+ mOpenHelper = new DatabaseHelper(mContext);
+
+ mMessageThread = new HandlerThread("AccountManagerService");
+ mMessageThread.start();
+ mMessageHandler = new MessageHandler(mMessageThread.getLooper());
+
+ mAuthenticatorCache = new AccountAuthenticatorCache(mContext);
+ mBindHelper = new AuthenticatorBindHelper(mContext, mAuthenticatorCache, mMessageHandler,
+ MESSAGE_CONNECTED, MESSAGE_DISCONNECTED);
+
+ mSimWatcher = new SimWatcher(mContext);
+ }
+
+ public String getPassword(Account account) {
+ long identityToken = clearCallingIdentity();
+ try {
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
+ ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+ new String[]{account.mName, account.mType}, null, null, null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getString(0);
+ }
+ return null;
+ } finally {
+ cursor.close();
+ }
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public String getUserData(Account account, String key) {
+ long identityToken = clearCallingIdentity();
+ try {
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountId(db, account);
+ if (accountId < 0) {
+ return null;
+ }
+ Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_VALUE},
+ EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
+ new String[]{key}, null, null, null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getString(0);
+ }
+ return null;
+ } finally {
+ cursor.close();
+ }
+ } finally {
+ db.setTransactionSuccessful();
+ db.endTransaction();
+ }
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public String[] getAuthenticatorTypes() {
+ long identityToken = clearCallingIdentity();
+ try {
+ Collection<AccountAuthenticatorCache.ServiceInfo<String>> authenticatorCollection =
+ mAuthenticatorCache.getAllServices();
+ String[] types = new String[authenticatorCollection.size()];
+ int i = 0;
+ for (AccountAuthenticatorCache.ServiceInfo<String> authenticator
+ : authenticatorCollection) {
+ types[i] = authenticator.type;
+ i++;
+ }
+ return types;
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public Account[] getAccounts() {
+ long identityToken = clearCallingIdentity();
+ try {
+ return getAccountsByType(null);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public Account[] getAccountsByType(String accountType) {
+ long identityToken = clearCallingIdentity();
+ try {
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+
+ final String selection = accountType == null ? null : (ACCOUNTS_TYPE + "=?");
+ final String[] selectionArgs = accountType == null ? null : new String[]{accountType};
+ Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_NAME_TYPE_PROJECTION,
+ selection, selectionArgs, null, null, null);
+ try {
+ int i = 0;
+ Account[] accounts = new Account[cursor.getCount()];
+ while (cursor.moveToNext()) {
+ accounts[i] = new Account(cursor.getString(1), cursor.getString(2));
+ i++;
+ }
+ return accounts;
+ } finally {
+ cursor.close();
+ }
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public boolean addAccount(Account account, String password, Bundle extras) {
+ // fails if the account already exists
+ long identityToken = clearCallingIdentity();
+ try {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ long numMatches = DatabaseUtils.longForQuery(db,
+ "select count(*) from " + TABLE_ACCOUNTS
+ + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+ new String[]{account.mName, account.mType});
+ if (numMatches > 0) {
+ return false;
+ }
+ ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_NAME, account.mName);
+ values.put(ACCOUNTS_TYPE, account.mType);
+ values.put(ACCOUNTS_PASSWORD, password);
+ long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
+ if (accountId < 0) {
+ return false;
+ }
+ if (extras != null) {
+ for (String key : extras.keySet()) {
+ final String value = extras.getString(key);
+ if (insertExtra(db, accountId, key, value) < 0) {
+ return false;
+ }
+ }
+ }
+ db.setTransactionSuccessful();
+ sendAccountsChangedBroadcast();
+ return true;
+ } finally {
+ db.endTransaction();
+ }
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private long insertExtra(SQLiteDatabase db, long accountId, String key, String value) {
+ ContentValues values = new ContentValues();
+ values.put(EXTRAS_KEY, key);
+ values.put(EXTRAS_ACCOUNTS_ID, accountId);
+ values.put(EXTRAS_VALUE, value);
+ return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
+ }
+
+ public void removeAccount(Account account) {
+ long identityToken = clearCallingIdentity();
+ try {
+ final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+ new String[]{account.mName, account.mType});
+ sendAccountsChangedBroadcast();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void invalidateAuthToken(String accountType, String authToken) {
+ long identityToken = clearCallingIdentity();
+ try {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ invalidateAuthToken(db, accountType, authToken);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private void invalidateAuthToken(SQLiteDatabase db, String accountType, String authToken) {
+ Cursor cursor = db.rawQuery(
+ "SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
+ + ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
+ + ", " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
+ + " FROM " + TABLE_ACCOUNTS
+ + " JOIN " + TABLE_AUTHTOKENS
+ + " ON " + TABLE_ACCOUNTS + "." + ACCOUNTS_ID
+ + " = " + AUTHTOKENS_ACCOUNTS_ID
+ + " WHERE " + AUTHTOKENS_AUTHTOKEN + " = ? AND "
+ + TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
+ new String[]{authToken, accountType});
+ try {
+ while (cursor.moveToNext()) {
+ long authTokenId = cursor.getLong(0);
+ String accountName = cursor.getString(1);
+ String authTokenType = cursor.getString(2);
+ db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+
+ private boolean saveAuthTokenToDatabase(Account account, String type, String authToken) {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountId(db, account);
+ if (accountId < 0) {
+ return false;
+ }
+ db.delete(TABLE_AUTHTOKENS,
+ AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
+ new String[]{type});
+ ContentValues values = new ContentValues();
+ values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
+ values.put(AUTHTOKENS_TYPE, type);
+ values.put(AUTHTOKENS_AUTHTOKEN, authToken);
+ if (db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
+ db.setTransactionSuccessful();
+ return true;
+ }
+ return false;
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ public String readAuthTokenFromDatabase(Account account, String authTokenType) {
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountId(db, account);
+ if (accountId < 0) {
+ return null;
+ }
+ return getAuthToken(db, accountId, authTokenType);
+ } finally {
+ db.setTransactionSuccessful();
+ db.endTransaction();
+ }
+ }
+
+ public String peekAuthToken(Account account, String authTokenType) {
+ long identityToken = clearCallingIdentity();
+ try {
+ return readAuthTokenFromDatabase(account, authTokenType);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void setAuthToken(Account account, String authTokenType, String authToken) {
+ long identityToken = clearCallingIdentity();
+ try {
+ cacheAuthToken(account, authTokenType, authToken);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void setPassword(Account account, String password) {
+ long identityToken = clearCallingIdentity();
+ try {
+ ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_PASSWORD, password);
+ mOpenHelper.getWritableDatabase().update(TABLE_ACCOUNTS, values,
+ ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+ new String[]{account.mName, account.mType});
+ sendAccountsChangedBroadcast();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private void sendAccountsChangedBroadcast() {
+ mContext.sendBroadcast(ACCOUNTS_CHANGED_INTENT);
+ }
+
+ public void clearPassword(Account account) {
+ long identityToken = clearCallingIdentity();
+ try {
+ setPassword(account, null);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void setUserData(Account account, String key, String value) {
+ long identityToken = clearCallingIdentity();
+ try {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountId(db, account);
+ if (accountId < 0) {
+ return;
+ }
+ long extrasId = getExtrasId(db, accountId, key);
+ if (extrasId < 0 ) {
+ extrasId = insertExtra(db, accountId, key, value);
+ if (extrasId < 0) {
+ return;
+ }
+ } else {
+ ContentValues values = new ContentValues();
+ values.put(EXTRAS_VALUE, value);
+ if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
+ return;
+ }
+
+ }
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void getAuthToken(IAccountManagerResponse response, final Account account,
+ final String authTokenType, final boolean notifyOnAuthFailure,
+ final boolean expectActivityLaunch, final Bundle loginOptions) {
+ long identityToken = clearCallingIdentity();
+ try {
+ String authToken = readAuthTokenFromDatabase(account, authTokenType);
+ if (authToken != null) {
+ try {
+ Bundle result = new Bundle();
+ result.putString(Constants.AUTHTOKEN_KEY, authToken);
+ result.putString(Constants.ACCOUNT_NAME_KEY, account.mName);
+ result.putString(Constants.ACCOUNT_TYPE_KEY, account.mType);
+ response.onResult(result);
+ } catch (RemoteException e) {
+ // if the caller is dead then there is no one to care about remote exceptions
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "failure while notifying response", e);
+ }
+ }
+ return;
+ }
+
+ new Session(response, account.mType, expectActivityLaunch) {
+ protected String toDebugString(long now) {
+ if (loginOptions != null) loginOptions.keySet();
+ return super.toDebugString(now) + ", getAuthToken"
+ + ", " + account
+ + ", authTokenType " + authTokenType
+ + ", loginOptions " + loginOptions
+ + ", notifyOnAuthFailure " + notifyOnAuthFailure;
+ }
+
+ public void run() throws RemoteException {
+ mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
+ }
+
+ public void onResult(Bundle result) {
+ if (result != null) {
+ String authToken = result.getString(Constants.AUTHTOKEN_KEY);
+ if (authToken != null) {
+ String name = result.getString(Constants.ACCOUNT_NAME_KEY);
+ String type = result.getString(Constants.ACCOUNT_TYPE_KEY);
+ if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
+ onError(Constants.ERROR_CODE_INVALID_RESPONSE,
+ "the type and name should not be empty");
+ return;
+ }
+ cacheAuthToken(new Account(name, type), authTokenType, authToken);
+ }
+
+ Intent intent = result.getParcelable(Constants.INTENT_KEY);
+ if (intent != null && notifyOnAuthFailure) {
+ doNotification(result.getString(Constants.AUTH_FAILED_MESSAGE_KEY),
+ intent);
+ }
+ }
+ super.onResult(result);
+ }
+ }.bind();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+
+ public void addAcount(final IAccountManagerResponse response, final String accountType,
+ final String authTokenType, final String[] requiredFeatures,
+ final boolean expectActivityLaunch, final Bundle options) {
+ long identityToken = clearCallingIdentity();
+ try {
+ new Session(response, accountType, expectActivityLaunch) {
+ public void run() throws RemoteException {
+ mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
+ options);
+ }
+
+ protected String toDebugString(long now) {
+ return super.toDebugString(now) + ", addAccount"
+ + ", accountType " + accountType
+ + ", requiredFeatures "
+ + (requiredFeatures != null
+ ? TextUtils.join(",", requiredFeatures)
+ : null);
+ }
+ }.bind();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void confirmCredentials(IAccountManagerResponse response,
+ final Account account, final boolean expectActivityLaunch) {
+ long identityToken = clearCallingIdentity();
+ try {
+ new Session(response, account.mType, expectActivityLaunch) {
+ public void run() throws RemoteException {
+ mAuthenticator.confirmCredentials(this, account);
+ }
+ protected String toDebugString(long now) {
+ return super.toDebugString(now) + ", confirmCredentials"
+ + ", " + account;
+ }
+ }.bind();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void confirmPassword(IAccountManagerResponse response, final Account account,
+ final String password) {
+ long identityToken = clearCallingIdentity();
+ try {
+ new Session(response, account.mType, false /* expectActivityLaunch */) {
+ public void run() throws RemoteException {
+ mAuthenticator.confirmPassword(this, account, password);
+ }
+ protected String toDebugString(long now) {
+ return super.toDebugString(now) + ", confirmPassword"
+ + ", " + account;
+ }
+ }.bind();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void updateCredentials(IAccountManagerResponse response, final Account account,
+ final String authTokenType, final boolean expectActivityLaunch,
+ final Bundle loginOptions) {
+ long identityToken = clearCallingIdentity();
+ try {
+ new Session(response, account.mType, expectActivityLaunch) {
+ public void run() throws RemoteException {
+ mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
+ }
+ protected String toDebugString(long now) {
+ if (loginOptions != null) loginOptions.keySet();
+ return super.toDebugString(now) + ", updateCredentials"
+ + ", " + account
+ + ", authTokenType " + authTokenType
+ + ", loginOptions " + loginOptions;
+ }
+ }.bind();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void editProperties(IAccountManagerResponse response, final String accountType,
+ final boolean expectActivityLaunch) {
+ long identityToken = clearCallingIdentity();
+ try {
+ new Session(response, accountType, expectActivityLaunch) {
+ public void run() throws RemoteException {
+ mAuthenticator.editProperties(this, mAccountType);
+ }
+ protected String toDebugString(long now) {
+ return super.toDebugString(now) + ", editProperties"
+ + ", accountType " + accountType;
+ }
+ }.bind();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private class GetAccountsByTypeAndFeatureSession extends Session {
+ private final String[] mFeatures;
+ private volatile Account[] mAccountsOfType = null;
+ private volatile ArrayList<Account> mAccountsWithFeatures = null;
+ private volatile int mCurrentAccount = 0;
+
+ public GetAccountsByTypeAndFeatureSession(IAccountManagerResponse response,
+ String type, String[] features) {
+ super(response, type, false /* expectActivityLaunch */);
+ mFeatures = features;
+ }
+
+ public void run() throws RemoteException {
+ mAccountsOfType = getAccountsByType(mAccountType);
+ // check whether each account matches the requested features
+ mAccountsWithFeatures = new ArrayList<Account>(mAccountsOfType.length);
+ mCurrentAccount = 0;
+
+ checkAccount();
+ }
+
+ public void checkAccount() {
+ if (mCurrentAccount >= mAccountsOfType.length) {
+ sendResult();
+ return;
+ }
+
+ try {
+ mAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
+ } catch (RemoteException e) {
+ onError(Constants.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
+ }
+ }
+
+ public void onResult(Bundle result) {
+ mNumResults++;
+ if (result == null) {
+ onError(Constants.ERROR_CODE_INVALID_RESPONSE, "null bundle");
+ return;
+ }
+ if (result.getBoolean(Constants.BOOLEAN_RESULT_KEY, false)) {
+ mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
+ }
+ mCurrentAccount++;
+ checkAccount();
+ }
+
+ public void sendResult() {
+ IAccountManagerResponse response = getResponseAndClose();
+ if (response != null) {
+ try {
+ Account[] accounts = new Account[mAccountsWithFeatures.size()];
+ for (int i = 0; i < accounts.length; i++) {
+ accounts[i] = mAccountsWithFeatures.get(i);
+ }
+ Bundle result = new Bundle();
+ result.putParcelableArray(Constants.ACCOUNTS_KEY, accounts);
+ response.onResult(result);
+ } catch (RemoteException e) {
+ // if the caller is dead then there is no one to care about remote exceptions
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "failure while notifying response", e);
+ }
+ }
+ }
+ }
+
+
+ protected String toDebugString(long now) {
+ return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
+ + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
+ }
+ }
+ public void getAccountsByTypeAndFeatures(IAccountManagerResponse response,
+ String type, String[] features) {
+ if (type == null) {
+ if (response != null) {
+ try {
+ response.onError(Constants.ERROR_CODE_BAD_ARGUMENTS, "type is null");
+ } catch (RemoteException e) {
+ // ignore this
+ }
+ }
+ return;
+ }
+ long identityToken = clearCallingIdentity();
+ try {
+ new GetAccountsByTypeAndFeatureSession(response, type, features).bind();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private boolean cacheAuthToken(Account account, String authTokenType, String authToken) {
+ return saveAuthTokenToDatabase(account, authTokenType, authToken);
+ }
+
+ private long getAccountId(SQLiteDatabase db, Account account) {
+ Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
+ "name=? AND type=?", new String[]{account.mName, account.mType}, null, null, null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getLong(0);
+ }
+ return -1;
+ } finally {
+ cursor.close();
+ }
+ }
+
+ private long getExtrasId(SQLiteDatabase db, long accountId, String key) {
+ Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_ID},
+ EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
+ new String[]{key}, null, null, null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getLong(0);
+ }
+ return -1;
+ } finally {
+ cursor.close();
+ }
+ }
+
+ private String getAuthToken(SQLiteDatabase db, long accountId, String authTokenType) {
+ Cursor cursor = db.query(TABLE_AUTHTOKENS, new String[]{AUTHTOKENS_AUTHTOKEN},
+ AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
+ new String[]{authTokenType},
+ null, null, null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getString(0);
+ }
+ return null;
+ } finally {
+ cursor.close();
+ }
+ }
+
+ private abstract class Session extends IAccountAuthenticatorResponse.Stub
+ implements AuthenticatorBindHelper.Callback, IBinder.DeathRecipient {
+ IAccountManagerResponse mResponse;
+ final String mAccountType;
+ final boolean mExpectActivityLaunch;
+ final long mCreationTime;
+
+ public int mNumResults = 0;
+ private int mNumRequestContinued = 0;
+ private int mNumErrors = 0;
+
+
+ IAccountAuthenticator mAuthenticator = null;
+
+ public Session(IAccountManagerResponse response, String accountType,
+ boolean expectActivityLaunch) {
+ super();
+ if (response == null) throw new IllegalArgumentException("response is null");
+ if (accountType == null) throw new IllegalArgumentException("accountType is null");
+ mResponse = response;
+ mAccountType = accountType;
+ mExpectActivityLaunch = expectActivityLaunch;
+ mCreationTime = SystemClock.elapsedRealtime();
+ synchronized (mSessions) {
+ mSessions.put(toString(), this);
+ }
+ try {
+ response.asBinder().linkToDeath(this, 0 /* flags */);
+ } catch (RemoteException e) {
+ mResponse = null;
+ binderDied();
+ }
+ }
+
+ IAccountManagerResponse getResponseAndClose() {
+ if (mResponse == null) {
+ // this session has already been closed
+ return null;
+ }
+ IAccountManagerResponse response = mResponse;
+ close(); // this clears mResponse so we need to save the response before this call
+ return response;
+ }
+
+ private void close() {
+ synchronized (mSessions) {
+ if (mSessions.remove(toString()) == null) {
+ // the session was already closed, so bail out now
+ return;
+ }
+ }
+ if (mResponse != null) {
+ // stop listening for response deaths
+ mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
+
+ // clear this so that we don't accidentally send any further results
+ mResponse = null;
+ }
+ cancelTimeout();
+ unbind();
+ }
+
+ public void binderDied() {
+ mResponse = null;
+ close();
+ }
+
+ protected String toDebugString() {
+ return toDebugString(SystemClock.elapsedRealtime());
+ }
+
+ protected String toDebugString(long now) {
+ return "Session: expectLaunch " + mExpectActivityLaunch
+ + ", connected " + (mAuthenticator != null)
+ + ", stats (" + mNumResults + "/" + mNumRequestContinued
+ + "/" + mNumErrors + ")"
+ + ", lifetime " + ((now - mCreationTime) / 1000.0);
+ }
+
+ void bind() {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
+ }
+ if (!mBindHelper.bind(mAccountType, this)) {
+ Log.d(TAG, "bind attempt failed for " + toDebugString());
+ onError(Constants.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
+ }
+ }
+
+ private void unbind() {
+ if (mAuthenticator != null) {
+ mAuthenticator = null;
+ mBindHelper.unbind(this);
+ }
+ }
+
+ public void scheduleTimeout() {
+ mMessageHandler.sendMessageDelayed(
+ mMessageHandler.obtainMessage(MESSAGE_TIMED_OUT, this), TIMEOUT_DELAY_MS);
+ }
+
+ public void cancelTimeout() {
+ mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
+ }
+
+ public void onConnected(IBinder service) {
+ mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
+ try {
+ run();
+ } catch (RemoteException e) {
+ onError(Constants.ERROR_CODE_REMOTE_EXCEPTION,
+ "remote exception");
+ }
+ }
+
+ public abstract void run() throws RemoteException;
+
+ public void onDisconnected() {
+ mAuthenticator = null;
+ IAccountManagerResponse response = getResponseAndClose();
+ if (response != null) {
+ onError(Constants.ERROR_CODE_REMOTE_EXCEPTION,
+ "disconnected");
+ }
+ }
+
+ public void onTimedOut() {
+ IAccountManagerResponse response = getResponseAndClose();
+ if (response != null) {
+ onError(Constants.ERROR_CODE_REMOTE_EXCEPTION,
+ "timeout");
+ }
+ }
+
+ public void onResult(Bundle result) {
+ mNumResults++;
+ if (result != null && !TextUtils.isEmpty(result.getString(Constants.AUTHTOKEN_KEY))) {
+ cancelNotification();
+ }
+ IAccountManagerResponse response;
+ if (mExpectActivityLaunch && result != null
+ && result.containsKey(Constants.INTENT_KEY)) {
+ response = mResponse;
+ } else {
+ response = getResponseAndClose();
+ }
+ if (response != null) {
+ try {
+ if (result == null) {
+ response.onError(Constants.ERROR_CODE_INVALID_RESPONSE,
+ "null bundle returned");
+ } else {
+ response.onResult(result);
+ }
+ } catch (RemoteException e) {
+ // if the caller is dead then there is no one to care about remote exceptions
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "failure while notifying response", e);
+ }
+ }
+ }
+ }
+
+ public void onRequestContinued() {
+ mNumRequestContinued++;
+ }
+
+ public void onError(int errorCode, String errorMessage) {
+ mNumErrors++;
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Session.onError: " + errorCode + ", " + errorMessage);
+ }
+ IAccountManagerResponse response = getResponseAndClose();
+ if (response != null) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Session.onError: responding");
+ }
+ try {
+ response.onError(errorCode, errorMessage);
+ } catch (RemoteException e) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
+ }
+ }
+ } else {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Session.onError: already closed");
+ }
+ }
+ }
+ }
+
+ private class MessageHandler extends Handler {
+ MessageHandler(Looper looper) {
+ super(looper);
+ }
+
+ public void handleMessage(Message msg) {
+ if (mBindHelper.handleMessage(msg)) {
+ return;
+ }
+ switch (msg.what) {
+ case MESSAGE_TIMED_OUT:
+ Session session = (Session)msg.obj;
+ session.onTimedOut();
+ break;
+
+ default:
+ throw new IllegalStateException("unhandled message: " + msg.what);
+ }
+ }
+ }
+
+ private class DatabaseHelper extends SQLiteOpenHelper {
+ public DatabaseHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
+ + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + ACCOUNTS_NAME + " TEXT NOT NULL, "
+ + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+ + ACCOUNTS_PASSWORD + " TEXT, "
+ + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+
+ db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " ( "
+ + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
+ + AUTHTOKENS_TYPE + " TEXT NOT NULL, "
+ + AUTHTOKENS_AUTHTOKEN + " TEXT, "
+ + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
+
+ db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
+ + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + EXTRAS_ACCOUNTS_ID + " INTEGER, "
+ + EXTRAS_KEY + " TEXT NOT NULL, "
+ + EXTRAS_VALUE + " TEXT, "
+ + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
+
+ db.execSQL("CREATE TABLE " + TABLE_META + " ( "
+ + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
+ + META_VALUE + " TEXT)");
+
+ db.execSQL(""
+ + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
+ + " BEGIN"
+ + " DELETE FROM " + TABLE_AUTHTOKENS
+ + " WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+ + " DELETE FROM " + TABLE_EXTRAS
+ + " WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+ + " END");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
+
+ if (oldVersion == 1) {
+ db.execSQL(""
+ + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
+ + " BEGIN"
+ + " DELETE FROM " + TABLE_AUTHTOKENS
+ + " WHERE " + AUTHTOKENS_ACCOUNTS_ID + " =OLD." + ACCOUNTS_ID + " ;"
+ + " DELETE FROM " + TABLE_EXTRAS
+ + " WHERE " + EXTRAS_ACCOUNTS_ID + " =OLD." + ACCOUNTS_ID + " ;"
+ + " END");
+ oldVersion++;
+ }
+ }
+
+ @Override
+ public void onOpen(SQLiteDatabase db) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DATABASE_NAME);
+ }
+ }
+
+ private void setMetaValue(String key, String value) {
+ ContentValues values = new ContentValues();
+ values.put(META_KEY, key);
+ values.put(META_VALUE, value);
+ mOpenHelper.getWritableDatabase().replace(TABLE_META, META_KEY, values);
+ }
+
+ private String getMetaValue(String key) {
+ Cursor c = mOpenHelper.getReadableDatabase().query(TABLE_META,
+ new String[]{META_VALUE}, META_KEY + "=?", new String[]{key}, null, null, null);
+ try {
+ if (c.moveToNext()) {
+ return c.getString(0);
+ }
+ return null;
+ } finally {
+ c.close();
+ }
+ }
+
+ private class SimWatcher extends BroadcastReceiver {
+ public SimWatcher(Context context) {
+ // Re-scan the SIM card when the SIM state changes, and also if
+ // the disk recovers from a full state (we may have failed to handle
+ // things properly while the disk was full).
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
+ context.registerReceiver(this, filter);
+ }
+
+ /**
+ * Compare the IMSI to the one stored in the login service's
+ * database. If they differ, erase all passwords and
+ * authtokens (and store the new IMSI).
+ */
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Check IMSI on every update; nothing happens if the IMSI is missing or unchanged.
+ String imsi = ((TelephonyManager) context.getSystemService(
+ Context.TELEPHONY_SERVICE)).getSubscriberId();
+ if (TextUtils.isEmpty(imsi)) return;
+
+ String storedImsi = getMetaValue("imsi");
+
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "current IMSI=" + imsi + "; stored IMSI=" + storedImsi);
+ }
+
+ if (!imsi.equals(storedImsi) && !"initial".equals(storedImsi)) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "wiping all passwords and authtokens");
+ }
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ db.execSQL("DELETE from " + TABLE_AUTHTOKENS);
+ db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_PASSWORD + " = ''");
+ sendAccountsChangedBroadcast();
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ }
+ setMetaValue("imsi", imsi);
+ }
+ }
+
+ public IBinder onBind(Intent intent) {
+ return asBinder();
+ }
+
+ protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+ synchronized (mSessions) {
+ final long now = SystemClock.elapsedRealtime();
+ fout.println("AccountManagerService: " + mSessions.size() + " sessions");
+ for (Session session : mSessions.values()) {
+ fout.println(" " + session.toDebugString(now));
+ }
+ }
+
+ fout.println();
+
+ mAuthenticatorCache.dump(fd, fout, args);
+ }
+
+ private void doNotification(CharSequence message, Intent intent) {
+ long identityToken = clearCallingIdentity();
+ try {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "doNotification: " + message + " intent:" + intent);
+ }
+
+ Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
+ 0 /* when */);
+ n.setLatestEventInfo(mContext, mContext.getText(R.string.notification_title), message,
+ PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
+ ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
+ .notify(NOTIFICATION_ID, n);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private void cancelNotification() {
+ long identityToken = clearCallingIdentity();
+ try {
+ ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
+ .cancel(NOTIFICATION_ID);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+}
diff --git a/core/java/android/accounts/AccountMonitor.java b/core/java/android/accounts/AccountMonitor.java
deleted file mode 100644
index f21385e..0000000
--- a/core/java/android/accounts/AccountMonitor.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * 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.
- */
-
-package android.accounts;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.database.SQLException;
-import android.os.IBinder;
-import android.os.Process;
-import android.os.RemoteException;
-import android.util.Log;
-
-/**
- * A helper class that calls back on the provided
- * AccountMonitorListener with the set of current accounts both when
- * it gets created and whenever the set changes. It does this by
- * binding to the AccountsService and registering to receive the
- * intent broadcast when the set of accounts is changed. The
- * connection to the accounts service is only made when it needs to
- * fetch the current list of accounts (that is, when the
- * AccountMonitor is first created, and when the intent is received).
- */
-public class AccountMonitor extends BroadcastReceiver implements ServiceConnection {
- private final Context mContext;
- private final AccountMonitorListener mListener;
- private boolean mClosed = false;
- private int pending = 0;
-
- // This thread runs in the background and runs the code to update accounts
- // in the listener.
- private class AccountUpdater extends Thread {
- private IBinder mService;
-
- public AccountUpdater(IBinder service) {
- mService = service;
- }
-
- @Override
- public void run() {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- IAccountsService accountsService = IAccountsService.Stub.asInterface(mService);
- String[] accounts = null;
- do {
- try {
- accounts = accountsService.getAccounts();
- } catch (RemoteException e) {
- // if the service was killed then the system will restart it and when it does we
- // will get another onServiceConnected, at which point we will do a notify.
- Log.w("AccountMonitor", "Remote exception when getting accounts", e);
- return;
- }
-
- synchronized (AccountMonitor.this) {
- --pending;
- if (pending == 0) {
- break;
- }
- }
- } while (true);
-
- mContext.unbindService(AccountMonitor.this);
-
- try {
- mListener.onAccountsUpdated(accounts);
- } catch (SQLException e) {
- // Better luck next time. If the problem was disk-full,
- // the STORAGE_OK intent will re-trigger the update.
- Log.e("AccountMonitor", "Can't update accounts", e);
- }
- }
- }
-
- /**
- * Initializes the AccountMonitor and initiates a bind to the
- * AccountsService to get the initial account list. For 1.0,
- * the "list" is always a single account.
- *
- * @param context the context we are running in
- * @param listener the user to notify when the account set changes
- */
- public AccountMonitor(Context context, AccountMonitorListener listener) {
- if (listener == null) {
- throw new IllegalArgumentException("listener is null");
- }
-
- mContext = context;
- mListener = listener;
-
- // Register a broadcast receiver to monitor account changes
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(AccountsServiceConstants.LOGIN_ACCOUNTS_CHANGED_ACTION);
- intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK); // To recover from disk-full.
- mContext.registerReceiver(this, intentFilter);
-
- // Send the listener the initial state now.
- notifyListener();
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- notifyListener();
- }
-
- public void onServiceConnected(ComponentName className, IBinder service) {
- // Create a background thread to update the accounts.
- new AccountUpdater(service).start();
- }
-
- public void onServiceDisconnected(ComponentName className) {
- }
-
- private synchronized void notifyListener() {
- if (pending == 0) {
- // initiate the bind
- if (!mContext.bindService(AccountsServiceConstants.SERVICE_INTENT,
- this, Context.BIND_AUTO_CREATE)) {
- // This is normal if GLS isn't part of this build.
- Log.w("AccountMonitor",
- "Couldn't connect to " +
- AccountsServiceConstants.SERVICE_INTENT +
- " (Missing service?)");
- }
- } else {
- // already bound. bindService will not trigger another
- // call to onServiceConnected, so instead we make sure
- // that the existing background thread will call
- // getAccounts() after this function returns, by
- // incrementing pending.
- //
- // Yes, this else clause contains only a comment.
- }
- ++pending;
- }
-
- /**
- * calls close()
- * @throws Throwable
- */
- @Override
- protected void finalize() throws Throwable {
- close();
- super.finalize();
- }
-
- /**
- * Unregisters the account receiver. Consecutive calls to this
- * method are harmless, but also do nothing. Once this call is
- * made no more notifications will occur.
- */
- public synchronized void close() {
- if (!mClosed) {
- mContext.unregisterReceiver(this);
- mClosed = true;
- }
- }
-}
diff --git a/core/java/android/accounts/AccountsServiceConstants.java b/core/java/android/accounts/AccountsServiceConstants.java
deleted file mode 100644
index b882e7b..0000000
--- a/core/java/android/accounts/AccountsServiceConstants.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.accounts;
-
-import android.content.Intent;
-
-/**
- * Miscellaneous constants used by the AccountsService and its
- * clients.
- */
-// TODO: These constants *could* come directly from the
-// IAccountsService interface, but that's not possible since the
-// aidl compiler doesn't let you define constants (yet.)
-public class AccountsServiceConstants {
- /** This class is never instantiated. */
- private AccountsServiceConstants() {
- }
-
- /**
- * Action sent as a broadcast Intent by the AccountsService
- * when accounts are added to and/or removed from the device's
- * database, or when the primary account is changed.
- */
- public static final String LOGIN_ACCOUNTS_CHANGED_ACTION =
- "android.accounts.LOGIN_ACCOUNTS_CHANGED";
-
- /**
- * Action sent as a broadcast Intent by the AccountsService
- * when it starts up and no accounts are available (so some should be added).
- */
- public static final String LOGIN_ACCOUNTS_MISSING_ACTION =
- "android.accounts.LOGIN_ACCOUNTS_MISSING";
-
- /**
- * Action on the intent used to bind to the IAccountsService interface. This
- * is used for services that have multiple interfaces (allowing
- * them to differentiate the interface intended, and return the proper
- * Binder.)
- */
- private static final String ACCOUNTS_SERVICE_ACTION = "android.accounts.IAccountsService";
-
- /*
- * The intent uses a component in addition to the action to ensure the actual
- * accounts service is bound to (a malicious third-party app could
- * theoretically have a service with the same action).
- */
- /** The intent used to bind to the accounts service. */
- public static final Intent SERVICE_INTENT =
- new Intent()
- .setClassName("com.google.android.googleapps",
- "com.google.android.googleapps.GoogleLoginService")
- .setAction(ACCOUNTS_SERVICE_ACTION);
-
- /**
- * Checks whether the intent is to bind to the accounts service.
- *
- * @param bindIntent The Intent used to bind to the service.
- * @return Whether the intent is to bind to the accounts service.
- */
- public static final boolean isForAccountsService(Intent bindIntent) {
- String otherAction = bindIntent.getAction();
- return otherAction != null && otherAction.equals(ACCOUNTS_SERVICE_ACTION);
- }
-}
diff --git a/core/java/android/accounts/AuthenticatorBindHelper.java b/core/java/android/accounts/AuthenticatorBindHelper.java
new file mode 100644
index 0000000..9d2ccf6
--- /dev/null
+++ b/core/java/android/accounts/AuthenticatorBindHelper.java
@@ -0,0 +1,251 @@
+/*
+ * 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.accounts;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+/**
+ * A helper object that simplifies binding to Account Authenticators. It uses the
+ * {@link AccountAuthenticatorCache} to find the component name of the authenticators,
+ * allowing the user to bind by account name. It also allows multiple, simultaneous binds
+ * to the same authenticator, with each bind call guaranteed to return either
+ * {@link Callback#onConnected} or {@link Callback#onDisconnected} if the bind() call
+ * itself succeeds, even if the authenticator is already bound internally.
+ * @hide
+ */
+public class AuthenticatorBindHelper {
+ private static final String TAG = "Accounts";
+ private final Handler mHandler;
+ private final Context mContext;
+ private final int mMessageWhatConnected;
+ private final int mMessageWhatDisconnected;
+ private final Map<String, MyServiceConnection> mServiceConnections = Maps.newHashMap();
+ private final Map<String, ArrayList<Callback>> mServiceUsers = Maps.newHashMap();
+ private final AccountAuthenticatorCache mAuthenticatorCache;
+
+ public AuthenticatorBindHelper(Context context,
+ AccountAuthenticatorCache authenticatorCache, Handler handler,
+ int messageWhatConnected, int messageWhatDisconnected) {
+ mContext = context;
+ mHandler = handler;
+ mAuthenticatorCache = authenticatorCache;
+ mMessageWhatConnected = messageWhatConnected;
+ mMessageWhatDisconnected = messageWhatDisconnected;
+ }
+
+ public interface Callback {
+ void onConnected(IBinder service);
+ void onDisconnected();
+ }
+
+ public boolean bind(String authenticatorType, Callback callback) {
+ // if the authenticator is connecting or connected then return true
+ synchronized (mServiceConnections) {
+ if (mServiceConnections.containsKey(authenticatorType)) {
+ MyServiceConnection connection = mServiceConnections.get(authenticatorType);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "service connection already exists for " + authenticatorType);
+ }
+ mServiceUsers.get(authenticatorType).add(callback);
+ if (connection.mService != null) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "the service is connected, scheduling a connected message for "
+ + authenticatorType);
+ }
+ connection.scheduleCallbackConnectedMessage(callback);
+ } else {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "the service is *not* connected, waiting for for "
+ + authenticatorType);
+ }
+ }
+ return true;
+ }
+
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "there is no service connection for " + authenticatorType);
+ }
+
+ // otherwise find the component name for the authenticator and initiate a bind
+ // if no authenticator or the bind fails then return false, otherwise return true
+ AccountAuthenticatorCache.ServiceInfo authenticatorInfo =
+ mAuthenticatorCache.getServiceInfo(authenticatorType);
+ if (authenticatorInfo == null) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "there is no authenticator for " + authenticatorType
+ + ", bailing out");
+ }
+ return false;
+ }
+
+ MyServiceConnection connection = new MyServiceConnection(authenticatorType);
+
+ Intent intent = new Intent();
+ intent.setAction("android.accounts.AccountAuthenticator");
+ intent.setComponent(authenticatorInfo.componentName);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
+ }
+ if (!mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE)) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
+ }
+ return false;
+ }
+
+ mServiceConnections.put(authenticatorType, connection);
+ mServiceUsers.put(authenticatorType, Lists.newArrayList(callback));
+ return true;
+ }
+ }
+
+ public void unbind(Callback callbackToUnbind) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "unbinding callback " + callbackToUnbind);
+ }
+ synchronized (mServiceConnections) {
+ for (Map.Entry<String, ArrayList<Callback>> entry : mServiceUsers.entrySet()) {
+ final String authenticatorType = entry.getKey();
+ final ArrayList<Callback> serviceUsers = entry.getValue();
+ for (Callback callback : serviceUsers) {
+ if (callback == callbackToUnbind) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "found callback in service" + authenticatorType);
+ }
+ serviceUsers.remove(callbackToUnbind);
+ if (serviceUsers.isEmpty()) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "there are no more callbacks for service "
+ + authenticatorType + ", unbinding service");
+ }
+ unbindFromService(authenticatorType);
+ } else {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "leaving service " + authenticatorType
+ + " around since there are still callbacks using it");
+ }
+ }
+ return;
+ }
+ }
+ }
+ Log.e(TAG, "did not find callback " + callbackToUnbind + " in any of the services");
+ }
+ }
+
+ private void unbindFromService(String authenticatorType) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "unbindService from " + authenticatorType);
+ }
+ mContext.unbindService(mServiceConnections.get(authenticatorType));
+ mServiceUsers.remove(authenticatorType);
+ mServiceConnections.remove(authenticatorType);
+ }
+
+ private class ConnectedMessagePayload {
+ public final IBinder mService;
+ public final Callback mCallback;
+ public ConnectedMessagePayload(IBinder service, Callback callback) {
+ mService = service;
+ mCallback = callback;
+ }
+ }
+
+ private class MyServiceConnection implements ServiceConnection {
+ private final String mAuthenticatorType;
+ private IBinder mService = null;
+
+ public MyServiceConnection(String authenticatorType) {
+ mAuthenticatorType = authenticatorType;
+ }
+
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "onServiceConnected for account type " + mAuthenticatorType);
+ }
+ // post a message for each service user to tell them that the service is connected
+ synchronized (mServiceConnections) {
+ mService = service;
+ for (Callback callback : mServiceUsers.get(mAuthenticatorType)) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "the service became connected, scheduling a connected "
+ + "message for " + mAuthenticatorType);
+ }
+ scheduleCallbackConnectedMessage(callback);
+ }
+ }
+ }
+
+ private void scheduleCallbackConnectedMessage(Callback callback) {
+ final ConnectedMessagePayload payload =
+ new ConnectedMessagePayload(mService, callback);
+ mHandler.obtainMessage(mMessageWhatConnected, payload).sendToTarget();
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "onServiceDisconnected for account type " + mAuthenticatorType);
+ }
+ // post a message for each service user to tell them that the service is disconnected,
+ // and unbind from the service.
+ synchronized (mServiceConnections) {
+ for (Callback callback : mServiceUsers.get(mAuthenticatorType)) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "the service became disconnected, scheduling a "
+ + "disconnected message for "
+ + mAuthenticatorType);
+ }
+ mHandler.obtainMessage(mMessageWhatDisconnected, callback).sendToTarget();
+ }
+ unbindFromService(mAuthenticatorType);
+ }
+ }
+ }
+
+ boolean handleMessage(Message message) {
+ if (message.what == mMessageWhatConnected) {
+ ConnectedMessagePayload payload = (ConnectedMessagePayload)message.obj;
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "notifying callback " + payload.mCallback + " that it is connected");
+ }
+ payload.mCallback.onConnected(payload.mService);
+ return true;
+ } else if (message.what == mMessageWhatDisconnected) {
+ Callback callback = (Callback)message.obj;
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "notifying callback " + callback + " that it is disconnected");
+ }
+ callback.onDisconnected();
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/include/utils.h b/core/java/android/accounts/AuthenticatorException.java
index 30648b1..4023494 100644
--- a/include/utils.h
+++ b/core/java/android/accounts/AuthenticatorException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 The Android Open Source Project
+ * 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.
@@ -14,20 +14,19 @@
* limitations under the License.
*/
-//
-// Handy utility functions and portability code. This file includes all
-// of the generally-useful headers in the "utils" directory.
-//
-#ifndef _LIBS_UTILS_H
-#define _LIBS_UTILS_H
+package android.accounts;
-#include <utils/ported.h>
-#include <utils/Log.h>
-#include <utils/threads.h>
-#include <utils/Timers.h>
-#include <utils/List.h>
-#include <utils/string_array.h>
-#include <utils/misc.h>
-#include <utils/Errors.h>
-
-#endif // _LIBS_UTILS_H
+public class AuthenticatorException extends Exception {
+ public AuthenticatorException() {
+ super();
+ }
+ public AuthenticatorException(String message) {
+ super(message);
+ }
+ public AuthenticatorException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ public AuthenticatorException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/core/java/android/accounts/ChooseAccountActivity.java b/core/java/android/accounts/ChooseAccountActivity.java
new file mode 100644
index 0000000..83377f3
--- /dev/null
+++ b/core/java/android/accounts/ChooseAccountActivity.java
@@ -0,0 +1,78 @@
+/*
+ * 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.accounts;
+
+import android.app.ListActivity;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.view.View;
+import android.util.Log;
+
+public class ChooseAccountActivity extends ListActivity {
+ private static final String TAG = "AccountManager";
+ private Parcelable[] mAccounts = null;
+ private AccountManagerResponse mAccountManagerResponse = null;
+ private Bundle mResult;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (savedInstanceState == null) {
+ mAccounts = getIntent().getParcelableArrayExtra(Constants.ACCOUNTS_KEY);
+ mAccountManagerResponse =
+ getIntent().getParcelableExtra(Constants.ACCOUNT_MANAGER_RESPONSE_KEY);
+ } else {
+ mAccounts = savedInstanceState.getParcelableArray(Constants.ACCOUNTS_KEY);
+ mAccountManagerResponse =
+ savedInstanceState.getParcelable(Constants.ACCOUNT_MANAGER_RESPONSE_KEY);
+ }
+
+ String[] mAccountNames = new String[mAccounts.length];
+ for (int i = 0; i < mAccounts.length; i++) {
+ mAccountNames[i] = ((Account) mAccounts[i]).mName;
+ }
+
+ // Use an existing ListAdapter that will map an array
+ // of strings to TextViews
+ setListAdapter(new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_1, mAccountNames));
+ getListView().setTextFilterEnabled(true);
+ }
+
+ protected void onListItemClick(ListView l, View v, int position, long id) {
+ Account account = (Account) mAccounts[position];
+ Log.d(TAG, "selected account " + account);
+ Bundle bundle = new Bundle();
+ bundle.putString(Constants.ACCOUNT_NAME_KEY, account.mName);
+ bundle.putString(Constants.ACCOUNT_TYPE_KEY, account.mType);
+ mResult = bundle;
+ finish();
+ }
+
+ public void finish() {
+ if (mAccountManagerResponse != null) {
+ if (mResult != null) {
+ mAccountManagerResponse.onResult(mResult);
+ } else {
+ mAccountManagerResponse.onError(Constants.ERROR_CODE_CANCELED, "canceled");
+ }
+ }
+ super.finish();
+ }
+}
diff --git a/core/java/android/accounts/Constants.java b/core/java/android/accounts/Constants.java
new file mode 100644
index 0000000..b383c61
--- /dev/null
+++ b/core/java/android/accounts/Constants.java
@@ -0,0 +1,50 @@
+/*
+ * 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.accounts;
+
+public class Constants {
+ // this should never be instantiated
+ private Constants() {}
+
+ public static final int ERROR_CODE_REMOTE_EXCEPTION = 1;
+ public static final int ERROR_CODE_NETWORK_ERROR = 3;
+ public static final int ERROR_CODE_CANCELED = 4;
+ public static final int ERROR_CODE_INVALID_RESPONSE = 5;
+ public static final int ERROR_CODE_UNSUPPORTED_OPERATION = 6;
+ public static final int ERROR_CODE_BAD_ARGUMENTS = 7;
+
+ public static final String ACCOUNTS_KEY = "accounts";
+ public static final String AUTHENTICATOR_TYPES_KEY = "authenticator_types";
+ public static final String PASSWORD_KEY = "password";
+ public static final String USERDATA_KEY = "userdata";
+ public static final String AUTHTOKEN_KEY = "authtoken";
+ public static final String ACCOUNT_NAME_KEY = "authAccount";
+ public static final String ACCOUNT_TYPE_KEY = "accountType";
+ public static final String ERROR_CODE_KEY = "errorCode";
+ public static final String ERROR_MESSAGE_KEY = "errorMessage";
+ public static final String INTENT_KEY = "intent";
+ public static final String BOOLEAN_RESULT_KEY = "booleanResult";
+ public static final String ACCOUNT_AUTHENTICATOR_RESPONSE_KEY = "accountAuthenticatorResponse";
+ public static final String ACCOUNT_MANAGER_RESPONSE_KEY = "accountManagerResponse";
+ public static final String AUTH_FAILED_MESSAGE_KEY = "authFailedMessage";
+ /**
+ * Action sent as a broadcast Intent by the AccountsService
+ * when accounts are added to and/or removed from the device's
+ * database, or when the primary account is changed.
+ */
+ public static final String LOGIN_ACCOUNTS_CHANGED_ACTION =
+ "android.accounts.LOGIN_ACCOUNTS_CHANGED";
+}
diff --git a/core/java/android/accounts/Future1.java b/core/java/android/accounts/Future1.java
new file mode 100644
index 0000000..386cb6e
--- /dev/null
+++ b/core/java/android/accounts/Future1.java
@@ -0,0 +1,46 @@
+/*
+ * 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.accounts;
+
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * An extension of {@link Future} that provides wrappers for {@link #get()} that handle the various
+ * exceptions that {@link #get()} may return and rethrows them as exceptions specific to
+ * {@link AccountManager}.
+ */
+public interface Future1<V> extends Future<V> {
+ /**
+ * Wrapper for {@link Future#get()}. If the get() throws {@link InterruptedException} then the
+ * {@link Future1} is canceled and {@link OperationCanceledException} is thrown.
+ * @return the {@link android.os.Bundle} that is returned by get()
+ * @throws OperationCanceledException if get() throws the unchecked CancellationException
+ * or if the Future was interrupted.
+ */
+ V getResult() throws OperationCanceledException;
+
+ /**
+ * Wrapper for {@link Future#get()}. If the get() throws {@link InterruptedException} then the
+ * {@link Future1} is canceled and {@link OperationCanceledException} is thrown.
+ * @param timeout the maximum time to wait
+ * @param unit the time unit of the timeout argument
+ * @return the {@link android.os.Bundle} that is returned by {@link Future#get()}
+ * @throws OperationCanceledException if get() throws the unchecked
+ * {@link java.util.concurrent.CancellationException} or if the {@link Future1} was interrupted.
+ */
+ V getResult(long timeout, TimeUnit unit) throws OperationCanceledException;
+} \ No newline at end of file
diff --git a/libs/utils/executablepath_linux.cpp b/core/java/android/accounts/Future1Callback.java
index b8d2a3d..886671b 100644
--- a/libs/utils/executablepath_linux.cpp
+++ b/core/java/android/accounts/Future1Callback.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * 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.
@@ -13,18 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.accounts;
-#include <utils/executablepath.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <limits.h>
-#include <stdio.h>
-
-void executablepath(char exe[PATH_MAX])
-{
- char proc[100];
- sprintf(proc, "/proc/%d/exe", getpid());
-
- int err = readlink(proc, exe, PATH_MAX);
+public interface Future1Callback<V> {
+ void run(Future1<V> future);
}
-
diff --git a/core/java/android/accounts/Future2.java b/core/java/android/accounts/Future2.java
new file mode 100644
index 0000000..b2ea84f
--- /dev/null
+++ b/core/java/android/accounts/Future2.java
@@ -0,0 +1,57 @@
+/*
+ * 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.accounts;
+
+import android.os.Bundle;
+
+import java.io.IOException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * An extension of {@link Future} that provides wrappers for {@link #get()} that handle the various
+ * exceptions that {@link #get()} may return and rethrows them as exceptions specific to
+ * {@link AccountManager}.
+ */
+public interface Future2 extends Future<Bundle> {
+ /**
+ * Wrapper for {@link Future#get()}. If the get() throws {@link InterruptedException} then the
+ * {@link Future2} is canceled and {@link OperationCanceledException} is thrown.
+ * @return the {@link android.os.Bundle} that is returned by {@link Future#get()}
+ * @throws OperationCanceledException if get() throws the unchecked
+ * {@link java.util.concurrent.CancellationException} or if the {@link Future2} was interrupted.
+ * @throws IOException if the request was unable to complete due to a network error
+ * @throws AuthenticatorException if there was an error communicating with the
+ * {@link AbstractAccountAuthenticator}.
+ */
+ Bundle getResult()
+ throws OperationCanceledException, IOException, AuthenticatorException;
+
+ /**
+ * Wrapper for {@link Future#get()}. If the get() throws {@link InterruptedException} then the
+ * {@link Future2} is canceled and {@link OperationCanceledException} is thrown.
+ * @param timeout the maximum time to wait
+ * @param unit the time unit of the timeout argument
+ * @return the {@link android.os.Bundle} that is returned by {@link Future#get()}
+ * @throws OperationCanceledException if get() throws the unchecked
+ * {@link java.util.concurrent.CancellationException} or if the {@link Future2} was interrupted.
+ * @throws IOException if the request was unable to complete due to a network error
+ * @throws AuthenticatorException if there was an error communicating with the
+ * {@link AbstractAccountAuthenticator}.
+ */
+ Bundle getResult(long timeout, TimeUnit unit)
+ throws OperationCanceledException, IOException, AuthenticatorException;
+}
diff --git a/core/java/android/accounts/Future2Callback.java b/core/java/android/accounts/Future2Callback.java
new file mode 100644
index 0000000..7ef0c94
--- /dev/null
+++ b/core/java/android/accounts/Future2Callback.java
@@ -0,0 +1,20 @@
+/*
+ * 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.accounts;
+
+public interface Future2Callback {
+ void run(Future2 future);
+} \ No newline at end of file
diff --git a/core/java/android/accounts/IAccountAuthenticator.aidl b/core/java/android/accounts/IAccountAuthenticator.aidl
new file mode 100644
index 0000000..46a7144
--- /dev/null
+++ b/core/java/android/accounts/IAccountAuthenticator.aidl
@@ -0,0 +1,68 @@
+/*
+ * 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.accounts;
+
+import android.accounts.IAccountAuthenticatorResponse;
+import android.accounts.Account;
+import android.os.Bundle;
+
+/**
+ * Service that allows the interaction with an authentication server.
+ */
+oneway interface IAccountAuthenticator {
+ /**
+ * prompts the user for account information and adds the result to the IAccountManager
+ */
+ void addAccount(in IAccountAuthenticatorResponse response, String accountType,
+ String authTokenType, in String[] requiredFeatures, in Bundle options);
+
+ /**
+ * Checks that the account/password combination is valid.
+ * @deprecated
+ */
+ void confirmPassword(in IAccountAuthenticatorResponse response,
+ in Account account, String password);
+
+ /**
+ * prompts the user for the credentials of the account
+ */
+ void confirmCredentials(in IAccountAuthenticatorResponse response, in Account account);
+
+ /**
+ * gets the password by either prompting the user or querying the IAccountManager
+ */
+ void getAuthToken(in IAccountAuthenticatorResponse response, in Account account,
+ String authTokenType, in Bundle options);
+
+ /**
+ * prompts the user for a new password and writes it to the IAccountManager
+ */
+ void updateCredentials(in IAccountAuthenticatorResponse response, in Account account,
+ String authTokenType, in Bundle options);
+
+ /**
+ * launches an activity that lets the user edit and set the properties for an authenticator
+ */
+ void editProperties(in IAccountAuthenticatorResponse response, String accountType);
+
+ /**
+ * returns a Bundle where the boolean value BOOLEAN_RESULT_KEY is set if the account has the
+ * specified features
+ */
+ void hasFeatures(in IAccountAuthenticatorResponse response, in Account account,
+ in String[] features);
+}
diff --git a/core/java/android/accounts/IAccountAuthenticatorResponse.aidl b/core/java/android/accounts/IAccountAuthenticatorResponse.aidl
new file mode 100644
index 0000000..a9ac2f1
--- /dev/null
+++ b/core/java/android/accounts/IAccountAuthenticatorResponse.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.accounts;
+import android.os.Bundle;
+
+/**
+ * The interface used to return responses from an {@link IAccountAuthenticator}
+ */
+oneway interface IAccountAuthenticatorResponse {
+ void onResult(in Bundle value);
+ void onRequestContinued();
+ void onError(int errorCode, String errorMessage);
+}
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
new file mode 100644
index 0000000..5e37a1f
--- /dev/null
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -0,0 +1,62 @@
+/*
+ * 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.accounts;
+
+import android.accounts.IAccountManagerResponse;
+import android.accounts.Account;
+import android.os.Bundle;
+
+/**
+ * Central application service that provides account management.
+ * @hide
+ */
+interface IAccountManager {
+ String getPassword(in Account account);
+ String getUserData(in Account account, String key);
+ String[] getAuthenticatorTypes();
+ Account[] getAccounts();
+ Account[] getAccountsByType(String accountType);
+ boolean addAccount(in Account account, String password, in Bundle extras);
+ void removeAccount(in Account account);
+ void invalidateAuthToken(String accountType, String authToken);
+ String peekAuthToken(in Account account, String authTokenType);
+ void setAuthToken(in Account account, String authTokenType, String authToken);
+ void setPassword(in Account account, String password);
+ void clearPassword(in Account account);
+ void setUserData(in Account account, String key, String value);
+
+ void getAuthToken(in IAccountManagerResponse response, in Account account,
+ String authTokenType, boolean notifyOnAuthFailure, boolean expectActivityLaunch,
+ in Bundle options);
+ void addAcount(in IAccountManagerResponse response, String accountType,
+ String authTokenType, in String[] requiredFeatures, boolean expectActivityLaunch,
+ in Bundle options);
+ void updateCredentials(in IAccountManagerResponse response, in Account account,
+ String authTokenType, boolean expectActivityLaunch, in Bundle options);
+ void editProperties(in IAccountManagerResponse response, String accountType,
+ boolean expectActivityLaunch);
+ void confirmCredentials(in IAccountManagerResponse response, in Account account,
+ boolean expectActivityLaunch);
+ void getAccountsByTypeAndFeatures(in IAccountManagerResponse response, String accountType,
+ in String[] features);
+
+ /*
+ * @deprecated
+ */
+ void confirmPassword(in IAccountManagerResponse response, in Account account,
+ String password);
+}
diff --git a/core/java/android/accounts/IAccountManagerResponse.aidl b/core/java/android/accounts/IAccountManagerResponse.aidl
new file mode 100644
index 0000000..ca1203d
--- /dev/null
+++ b/core/java/android/accounts/IAccountManagerResponse.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.accounts;
+import android.os.Bundle;
+
+/**
+ * The interface used to return responses for asynchronous calls to the {@link IAccountManager}
+ * @hide
+ */
+oneway interface IAccountManagerResponse {
+ void onResult(in Bundle value);
+ void onError(int errorCode, String errorMessage);
+}
diff --git a/core/java/android/accounts/IAccountsService.aidl b/core/java/android/accounts/IAccountsService.aidl
deleted file mode 100644
index dda513c..0000000
--- a/core/java/android/accounts/IAccountsService.aidl
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.accounts;
-
-/**
- * Central application service that allows querying the list of accounts.
- */
-interface IAccountsService {
- /**
- * Gets the list of Accounts the user has previously logged
- * in to. Accounts are of the form "username@domain".
- * <p>
- * This method will return an empty array if the device doesn't
- * know about any accounts (yet).
- *
- * @return The accounts. The array will be zero-length if the
- * AccountsService doesn't know about any accounts yet.
- */
- String[] getAccounts();
-
- /**
- * This is an interim solution for bypassing a forgotten gesture on the
- * unlock screen (it is hidden, please make sure it stays this way!). This
- * will be *removed* when the unlock screen design supports additional
- * authenticators.
- * <p>
- * The user will be presented with username and password fields that are
- * called as parameters to this method. If true is returned, the user is
- * able to define a new gesture and get back into the system. If false, the
- * user can try again.
- *
- * @param username The username entered.
- * @param password The password entered.
- * @return Whether to allow the user to bypass the lock screen and define a
- * new gesture.
- * @hide (The package is already hidden, but just in case someone
- * unhides that, this should not be revealed.)
- */
- boolean shouldUnlock(String username, String password);
-}
diff --git a/core/java/android/accounts/NetworkErrorException.java b/core/java/android/accounts/NetworkErrorException.java
new file mode 100644
index 0000000..f855cc8
--- /dev/null
+++ b/core/java/android/accounts/NetworkErrorException.java
@@ -0,0 +1,31 @@
+/*
+ * 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.accounts;
+
+public class NetworkErrorException extends Exception {
+ public NetworkErrorException() {
+ super();
+ }
+ public NetworkErrorException(String message) {
+ super(message);
+ }
+ public NetworkErrorException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ public NetworkErrorException(Throwable cause) {
+ super(cause);
+ }
+} \ No newline at end of file
diff --git a/core/java/android/accounts/AccountMonitorListener.java b/core/java/android/accounts/OnAccountsUpdatedListener.java
index d0bd9a9..bd249d0 100644
--- a/core/java/android/accounts/AccountMonitorListener.java
+++ b/core/java/android/accounts/OnAccountsUpdatedListener.java
@@ -19,11 +19,11 @@ package android.accounts;
/**
* An interface that contains the callback used by the AccountMonitor
*/
-public interface AccountMonitorListener {
+public interface OnAccountsUpdatedListener {
/**
* This invoked when the AccountMonitor starts up and whenever the account
* set changes.
- * @param currentAccounts the current accounts
+ * @param accounts the current accounts
*/
- void onAccountsUpdated(String[] currentAccounts);
+ void onAccountsUpdated(Account[] accounts);
}
diff --git a/core/java/android/accounts/OperationCanceledException.java b/core/java/android/accounts/OperationCanceledException.java
new file mode 100644
index 0000000..2f2c164
--- /dev/null
+++ b/core/java/android/accounts/OperationCanceledException.java
@@ -0,0 +1,31 @@
+/*
+ * 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.accounts;
+
+public class OperationCanceledException extends Exception {
+ public OperationCanceledException() {
+ super();
+ }
+ public OperationCanceledException(String message) {
+ super(message);
+ }
+ public OperationCanceledException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ public OperationCanceledException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/core/java/android/accounts/package.html b/core/java/android/accounts/package.html
deleted file mode 100755
index c9f96a6..0000000
--- a/core/java/android/accounts/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<body>
-
-{@hide}
-
-</body>
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index 98bbf7b..34aeca1 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -92,6 +92,8 @@ import android.view.LayoutInflater;
import android.view.WindowManagerImpl;
import android.view.accessibility.AccessibilityManager;
import android.view.inputmethod.InputMethodManager;
+import android.accounts.AccountManager;
+import android.accounts.IAccountManager;
import java.io.File;
import java.io.FileInputStream;
@@ -150,6 +152,7 @@ class ApplicationContext extends Context {
private final static boolean DEBUG_ICONS = false;
private static final Object sSync = new Object();
+ private static AccountManager sAccountManager;
private static AlarmManager sAlarmManager;
private static PowerManager sPowerManager;
private static ConnectivityManager sConnectivityManager;
@@ -882,6 +885,8 @@ class ApplicationContext extends Context {
return getActivityManager();
} else if (ALARM_SERVICE.equals(name)) {
return getAlarmManager();
+ } else if (ACCOUNT_SERVICE.equals(name)) {
+ return getAccountManager();
} else if (POWER_SERVICE.equals(name)) {
return getPowerManager();
} else if (CONNECTIVITY_SERVICE.equals(name)) {
@@ -924,6 +929,17 @@ class ApplicationContext extends Context {
return null;
}
+ private AccountManager getAccountManager() {
+ synchronized (sSync) {
+ if (sAccountManager == null) {
+ IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
+ IAccountManager service = IAccountManager.Stub.asInterface(b);
+ sAccountManager = new AccountManager(this, service);
+ }
+ }
+ return sAccountManager;
+ }
+
private ActivityManager getActivityManager() {
synchronized (mSync) {
if (mActivityManager == null) {
diff --git a/core/java/android/bluetooth/BluetoothInputStream.java b/core/java/android/bluetooth/BluetoothInputStream.java
new file mode 100644
index 0000000..e6f501c
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothInputStream.java
@@ -0,0 +1,98 @@
+/*
+ * 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.bluetooth;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * BluetoothInputStream.
+ *
+ * Used to write to a Bluetooth socket.
+ *
+ * @hide
+ */
+/*package*/ final class BluetoothInputStream extends InputStream {
+ private BluetoothSocket mSocket;
+
+ /*package*/ BluetoothInputStream(BluetoothSocket s) {
+ mSocket = s;
+ }
+
+ /**
+ * Return number of bytes available before this stream will block.
+ */
+ public int available() throws IOException {
+ return mSocket.availableNative();
+ }
+
+ public void close() throws IOException {
+ mSocket.close();
+ }
+
+ /**
+ * Reads a single byte from this stream and returns it as an integer in the
+ * range from 0 to 255. Returns -1 if the end of the stream has been
+ * reached. Blocks until one byte has been read, the end of the source
+ * stream is detected or an exception is thrown.
+ *
+ * @return the byte read or -1 if the end of stream has been reached.
+ * @throws IOException
+ * if the stream is closed or another IOException occurs.
+ * @since Android 1.5
+ */
+ public int read() throws IOException {
+ byte b[] = new byte[1];
+ int ret = mSocket.readNative(b, 0, 1);
+ if (ret == 1) {
+ return (int)b[0];
+ } else {
+ return -1;
+ }
+ }
+
+ /**
+ * Reads at most {@code length} bytes from this stream and stores them in
+ * the byte array {@code b} starting at {@code offset}.
+ *
+ * @param b
+ * the byte array in which to store the bytes read.
+ * @param offset
+ * the initial position in {@code buffer} to store the bytes
+ * read from this stream.
+ * @param length
+ * the maximum number of bytes to store in {@code b}.
+ * @return the number of bytes actually read or -1 if the end of the stream
+ * has been reached.
+ * @throws IndexOutOfBoundsException
+ * if {@code offset < 0} or {@code length < 0}, or if
+ * {@code offset + length} is greater than the length of
+ * {@code b}.
+ * @throws IOException
+ * if the stream is closed or another IOException occurs.
+ * @since Android 1.5
+ */
+ public int read(byte[] b, int offset, int length) throws IOException {
+ if (b == null) {
+ throw new NullPointerException("byte array is null");
+ }
+ if ((offset | length) < 0 || length > b.length - offset) {
+ throw new ArrayIndexOutOfBoundsException("invalid offset or length");
+ }
+ return mSocket.readNative(b, offset, length);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothOutputStream.java b/core/java/android/bluetooth/BluetoothOutputStream.java
new file mode 100644
index 0000000..7e2ead4
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothOutputStream.java
@@ -0,0 +1,87 @@
+/*
+ * 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.bluetooth;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * BluetoothOutputStream.
+ *
+ * Used to read from a Bluetooth socket.
+ *
+ * @hide
+ */
+/*package*/ final class BluetoothOutputStream extends OutputStream {
+ private BluetoothSocket mSocket;
+
+ /*package*/ BluetoothOutputStream(BluetoothSocket s) {
+ mSocket = s;
+ }
+
+ /**
+ * Close this output stream and the socket associated with it.
+ */
+ public void close() throws IOException {
+ mSocket.close();
+ }
+
+ /**
+ * Writes a single byte to this stream. Only the least significant byte of
+ * the integer {@code oneByte} is written to the stream.
+ *
+ * @param oneByte
+ * the byte to be written.
+ * @throws IOException
+ * if an error occurs while writing to this stream.
+ * @since Android 1.0
+ */
+ public void write(int oneByte) throws IOException {
+ byte b[] = new byte[1];
+ b[0] = (byte)oneByte;
+ mSocket.writeNative(b, 0, 1);
+ }
+
+ /**
+ * Writes {@code count} bytes from the byte array {@code buffer} starting
+ * at position {@code offset} to this stream.
+ *
+ * @param b
+ * the buffer to be written.
+ * @param offset
+ * the start position in {@code buffer} from where to get bytes.
+ * @param count
+ * the number of bytes from {@code buffer} to write to this
+ * stream.
+ * @throws IOException
+ * if an error occurs while writing to this stream.
+ * @throws IndexOutOfBoundsException
+ * if {@code offset < 0} or {@code count < 0}, or if
+ * {@code offset + count} is bigger than the length of
+ * {@code buffer}.
+ * @since Android 1.0
+ */
+ public void write(byte[] b, int offset, int count) throws IOException {
+ if (b == null) {
+ throw new NullPointerException("buffer is null");
+ }
+ if ((offset | count) < 0 || count > b.length - offset) {
+ throw new IndexOutOfBoundsException("invalid offset or length");
+ }
+ mSocket.writeNative(b, offset, count);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
new file mode 100644
index 0000000..f3baeab
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -0,0 +1,150 @@
+/*
+ * 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.bluetooth;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * Server (listening) Bluetooth Socket.
+ *
+ * Currently only supports RFCOMM sockets.
+ *
+ * RFCOMM is a connection orientated, streaming transport over Bluetooth. It is
+ * also known as the Serial Port Profile (SPP).
+ *
+ * TODO: Consider exposing L2CAP sockets.
+ * TODO: Clean up javadoc grammer and formatting.
+ * TODO: Remove @hide
+ * @hide
+ */
+public final class BluetoothServerSocket implements Closeable {
+ private final BluetoothSocket mSocket;
+
+ /**
+ * Construct a listening, secure RFCOMM server socket.
+ * The remote device connecting to this socket will be authenticated and
+ * communication on this socket will be encrypted.
+ * Call #accept to retrieve connections to this socket.
+ * @return An RFCOMM BluetoothServerSocket
+ * @throws IOException On error, for example Bluetooth not available, or
+ * insufficient permissions.
+ */
+ public static BluetoothServerSocket listenUsingRfcommOn(int port) throws IOException {
+ BluetoothServerSocket socket = new BluetoothServerSocket(
+ BluetoothSocket.TYPE_RFCOMM, true, true, port);
+ try {
+ socket.mSocket.bindListenNative();
+ } catch (IOException e) {
+ try {
+ socket.close();
+ } catch (IOException e2) { }
+ throw e;
+ }
+ return socket;
+ }
+
+ /**
+ * Construct an unencrypted, unauthenticated, RFCOMM server socket.
+ * Call #accept to retrieve connections to this socket.
+ * @return An RFCOMM BluetoothServerSocket
+ * @throws IOException On error, for example Bluetooth not available, or
+ * insufficient permissions.
+ */
+ public static BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
+ BluetoothServerSocket socket = new BluetoothServerSocket(
+ BluetoothSocket.TYPE_RFCOMM, false, false, port);
+ try {
+ socket.mSocket.bindListenNative();
+ } catch (IOException e) {
+ try {
+ socket.close();
+ } catch (IOException e2) { }
+ throw e;
+ }
+ return socket;
+ }
+
+ /**
+ * Construct a SCO server socket.
+ * Call #accept to retrieve connections to this socket.
+ * @return A SCO BluetoothServerSocket
+ * @throws IOException On error, for example Bluetooth not available, or
+ * insufficient permissions.
+ */
+ public static BluetoothServerSocket listenUsingScoOn() throws IOException {
+ BluetoothServerSocket socket = new BluetoothServerSocket(
+ BluetoothSocket.TYPE_SCO, false, false, -1);
+ try {
+ socket.mSocket.bindListenNative();
+ } catch (IOException e) {
+ try {
+ socket.close();
+ } catch (IOException e2) { }
+ throw e;
+ }
+ return socket;
+ }
+
+ /**
+ * Construct a socket for incoming connections.
+ * @param type type of socket
+ * @param auth require the remote device to be authenticated
+ * @param encrypt require the connection to be encrypted
+ * @param port remote port
+ * @throws IOException On error, for example Bluetooth not available, or
+ * insufficient priveleges
+ */
+ private BluetoothServerSocket(int type, boolean auth, boolean encrypt, int port)
+ throws IOException {
+ mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, port);
+ }
+
+ /**
+ * Block until a connection is established.
+ * Returns a connected #BluetoothSocket. This server socket can be reused
+ * for subsequent incoming connections by calling #accept repeatedly.
+ * #close can be used to abort this call from another thread.
+ * @return A connected #BluetoothSocket
+ * @throws IOException On error, for example this call was aborted
+ */
+ public BluetoothSocket accept() throws IOException {
+ return accept(-1);
+ }
+
+ /**
+ * Block until a connection is established, with timeout.
+ * Returns a connected #BluetoothSocket. This server socket can be reused
+ * for subsequent incoming connections by calling #accept repeatedly.
+ * #close can be used to abort this call from another thread.
+ * @return A connected #BluetoothSocket
+ * @throws IOException On error, for example this call was aborted, or
+ * timeout
+ */
+ public BluetoothSocket accept(int timeout) throws IOException {
+ return mSocket.acceptNative(timeout);
+ }
+
+ /**
+ * Closes this socket.
+ * This will cause other blocking calls on this socket to immediately
+ * throw an IOException.
+ */
+ public void close() throws IOException {
+ mSocket.closeNative();
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
new file mode 100644
index 0000000..de1f326
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -0,0 +1,197 @@
+/*
+ * 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.bluetooth;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Represents a connected or connecting Bluetooth Socket.
+ *
+ * Currently only supports RFCOMM sockets.
+ *
+ * RFCOMM is a connection orientated, streaming transport over Bluetooth. It is
+ * also known as the Serial Port Profile (SPP).
+ *
+ * TODO: Consider exposing L2CAP sockets.
+ * TODO: Clean up javadoc grammer and formatting.
+ * TODO: Remove @hide
+ * @hide
+ */
+public final class BluetoothSocket implements Closeable {
+ /** Keep TYPE_RFCOMM etc in sync with BluetoothSocket.cpp */
+ /*package*/ static final int TYPE_RFCOMM = 1;
+ /*package*/ static final int TYPE_SCO = 2;
+ /*package*/ static final int TYPE_L2CAP = 3;
+
+ private final int mType; /* one of TYPE_RFCOMM etc */
+ private final int mPort; /* RFCOMM channel or L2CAP psm */
+ private final String mAddress; /* remote address */
+ private final boolean mAuth;
+ private final boolean mEncrypt;
+ private final BluetoothInputStream mInputStream;
+ private final BluetoothOutputStream mOutputStream;
+
+ private int mSocketData; /* used by native code only */
+
+ /**
+ * Construct a secure RFCOMM socket ready to start an outgoing connection.
+ * Call #connect on the returned #BluetoothSocket to begin the connection.
+ * The remote device will be authenticated and communication on this socket
+ * will be encrypted.
+ * @param address remote Bluetooth address that this socket can connect to
+ * @param port remote port
+ * @return an RFCOMM BluetoothSocket
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions.
+ */
+ public static BluetoothSocket createRfcommSocket(String address, int port)
+ throws IOException {
+ return new BluetoothSocket(TYPE_RFCOMM, -1, true, true, address, port);
+ }
+
+ /**
+ * Construct an insecure RFCOMM socket ready to start an outgoing
+ * connection.
+ * Call #connect on the returned #BluetoothSocket to begin the connection.
+ * The remote device will not be authenticated and communication on this
+ * socket will not be encrypted.
+ * @param address remote Bluetooth address that this socket can connect to
+ * @param port remote port
+ * @return An RFCOMM BluetoothSocket
+ * @throws IOException On error, for example Bluetooth not available, or
+ * insufficient permissions.
+ */
+ public static BluetoothSocket createInsecureRfcommSocket(String address, int port)
+ throws IOException {
+ return new BluetoothSocket(TYPE_RFCOMM, -1, false, false, address, port);
+ }
+
+ /**
+ * Construct a SCO socket ready to start an outgoing connection.
+ * Call #connect on the returned #BluetoothSocket to begin the connection.
+ * @param address remote Bluetooth address that this socket can connect to
+ * @return a SCO BluetoothSocket
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions.
+ */
+ public static BluetoothSocket createScoSocket(String address, int port)
+ throws IOException {
+ return new BluetoothSocket(TYPE_SCO, -1, true, true, address, port);
+ }
+
+ /**
+ * Construct a Bluetooth.
+ * @param type type of socket
+ * @param fd fd to use for connected socket, or -1 for a new socket
+ * @param auth require the remote device to be authenticated
+ * @param encrypt require the connection to be encrypted
+ * @param address remote Bluetooth address that this socket can connect to
+ * @param port remote port
+ * @throws IOException On error, for example Bluetooth not available, or
+ * insufficient priveleges
+ */
+ /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address,
+ int port) throws IOException {
+ mType = type;
+ mAuth = auth;
+ mEncrypt = encrypt;
+ mAddress = address;
+ mPort = port;
+ if (fd == -1) {
+ initSocketNative();
+ } else {
+ initSocketFromFdNative(fd);
+ }
+ mInputStream = new BluetoothInputStream(this);
+ mOutputStream = new BluetoothOutputStream(this);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /**
+ * Attempt to connect to a remote device.
+ * This method will block until a connection is made or the connection
+ * fails. If this method returns without an exception then this socket
+ * is now connected. #close can be used to abort this call from another
+ * thread.
+ * @throws IOException On error, for example connection failure
+ */
+ public void connect() throws IOException {
+ connectNative();
+ }
+
+ /**
+ * Closes this socket.
+ * This will cause other blocking calls on this socket to immediately
+ * throw an IOException.
+ */
+ public void close() throws IOException {
+ closeNative();
+ }
+
+ /**
+ * Return the address we are connecting, or connected, to.
+ * @return Bluetooth address, or null if this socket has not yet attempted
+ * or established a connection.
+ */
+ public String getAddress() {
+ return mAddress;
+ }
+
+ /**
+ * Get the input stream associated with this socket.
+ * The input stream will be returned even if the socket is not yet
+ * connected, but operations on that stream will throw IOException until
+ * the associated socket is connected.
+ * @return InputStream
+ */
+ public InputStream getInputStream() throws IOException {
+ return mInputStream;
+ }
+
+ /**
+ * Get the output stream associated with this socket.
+ * The output stream will be returned even if the socket is not yet
+ * connected, but operations on that stream will throw IOException until
+ * the associated socket is connected.
+ * @return OutputStream
+ */
+ public OutputStream getOutputStream() throws IOException {
+ return mOutputStream;
+ }
+
+ private native void initSocketNative() throws IOException;
+ private native void initSocketFromFdNative(int fd) throws IOException;
+ private native void connectNative() throws IOException;
+ /*package*/ native void bindListenNative() throws IOException;
+ /*package*/ native BluetoothSocket acceptNative(int timeout) throws IOException;
+ /*package*/ native int availableNative() throws IOException;
+ /*package*/ native int readNative(byte[] b, int offset, int length) throws IOException;
+ /*package*/ native int writeNative(byte[] b, int offset, int length) throws IOException;
+ /*package*/ native void closeNative() throws IOException;
+ private native void destroyNative() throws IOException;
+}
diff --git a/core/java/android/bluetooth/Database.java b/core/java/android/bluetooth/Database.java
deleted file mode 100644
index fef641a..0000000
--- a/core/java/android/bluetooth/Database.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * 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.
- */
-
-package android.bluetooth;
-
-import android.bluetooth.RfcommSocket;
-
-import android.util.Log;
-
-import java.io.*;
-import java.util.*;
-
-/**
- * The Android Bluetooth API is not finalized, and *will* change. Use at your
- * own risk.
- *
- * A low-level API to the Service Discovery Protocol (SDP) Database.
- *
- * Allows service records to be added to the local SDP database. Once added,
- * these services will be advertised to remote devices when they make SDP
- * queries on this device.
- *
- * Currently this API is a thin wrapper to the bluez SDP Database API. See:
- * http://wiki.bluez.org/wiki/Database
- * http://wiki.bluez.org/wiki/HOWTO/ManagingServiceRecords
- * @hide
- */
-public final class Database {
- private static Database mInstance;
-
- private static final String sLogName = "android.bluetooth.Database";
-
- /**
- * Class load time initialization
- */
- static {
- classInitNative();
- }
- private native static void classInitNative();
-
- /**
- * Private to enforce singleton property
- */
- private Database() {
- initializeNativeDataNative();
- }
- private native void initializeNativeDataNative();
-
- protected void finalize() throws Throwable {
- try {
- cleanupNativeDataNative();
- } finally {
- super.finalize();
- }
- }
- private native void cleanupNativeDataNative();
-
- /**
- * Singelton accessor
- * @return The singleton instance of Database
- */
- public static synchronized Database getInstance() {
- if (mInstance == null) {
- mInstance = new Database();
- }
- return mInstance;
- }
-
- /**
- * Advertise a service with an RfcommSocket.
- *
- * This adds the service the SDP Database with the following attributes
- * set: Service Name, Protocol Descriptor List, Service Class ID List
- * TODO: Construct a byte[] record directly, rather than via XML.
- * @param socket The rfcomm socket to advertise (by channel).
- * @param serviceName A short name for this service
- * @param uuid
- * Unique identifier for this service, by which clients
- * can search for your service
- * @return Handle to the new service record
- */
- public int advertiseRfcommService(RfcommSocket socket,
- String serviceName,
- UUID uuid) throws IOException {
- String xmlRecord =
- "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
- "<record>\n" +
- " <attribute id=\"0x0001\">\n" + // ServiceClassIDList
- " <sequence>\n" +
- " <uuid value=\""
- + uuid.toString() + // UUID for this service
- "\"/>\n" +
- " </sequence>\n" +
- " </attribute>\n" +
- " <attribute id=\"0x0004\">\n" + // ProtocolDescriptorList
- " <sequence>\n" +
- " <sequence>\n" +
- " <uuid value=\"0x0100\"/>\n" + // L2CAP
- " </sequence>\n" +
- " <sequence>\n" +
- " <uuid value=\"0x0003\"/>\n" + // RFCOMM
- " <uint8 value=\"" +
- socket.getPort() + // RFCOMM port
- "\" name=\"channel\"/>\n" +
- " </sequence>\n" +
- " </sequence>\n" +
- " </attribute>\n" +
- " <attribute id=\"0x0100\">\n" + // ServiceName
- " <text value=\"" + serviceName + "\"/>\n" +
- " </attribute>\n" +
- "</record>\n";
- Log.i(sLogName, xmlRecord);
- return addServiceRecordFromXml(xmlRecord);
- }
-
-
- /**
- * Add a new service record.
- * @param record The byte[] record
- * @return A handle to the new record
- */
- public synchronized int addServiceRecord(byte[] record) throws IOException {
- int handle = addServiceRecordNative(record);
- Log.i(sLogName, "Added SDP record: " + Integer.toHexString(handle));
- return handle;
- }
- private native int addServiceRecordNative(byte[] record)
- throws IOException;
-
- /**
- * Add a new service record, using XML.
- * @param record The record as an XML string
- * @return A handle to the new record
- */
- public synchronized int addServiceRecordFromXml(String record) throws IOException {
- int handle = addServiceRecordFromXmlNative(record);
- Log.i(sLogName, "Added SDP record: " + Integer.toHexString(handle));
- return handle;
- }
- private native int addServiceRecordFromXmlNative(String record)
- throws IOException;
-
- /**
- * Update an exisiting service record.
- * @param handle Handle to exisiting record
- * @param record The updated byte[] record
- */
- public synchronized void updateServiceRecord(int handle, byte[] record) {
- try {
- updateServiceRecordNative(handle, record);
- } catch (IOException e) {
- Log.e(getClass().toString(), e.getMessage());
- }
- }
- private native void updateServiceRecordNative(int handle, byte[] record)
- throws IOException;
-
- /**
- * Update an exisiting record, using XML.
- * @param handle Handle to exisiting record
- * @param record The record as an XML string.
- */
- public synchronized void updateServiceRecordFromXml(int handle, String record) {
- try {
- updateServiceRecordFromXmlNative(handle, record);
- } catch (IOException e) {
- Log.e(getClass().toString(), e.getMessage());
- }
- }
- private native void updateServiceRecordFromXmlNative(int handle, String record)
- throws IOException;
-
- /**
- * Remove a service record.
- * It is only possible to remove service records that were added by the
- * current connection.
- * @param handle Handle to exisiting record to be removed
- */
- public synchronized void removeServiceRecord(int handle) {
- try {
- removeServiceRecordNative(handle);
- } catch (IOException e) {
- Log.e(getClass().toString(), e.getMessage());
- }
- }
- private native void removeServiceRecordNative(int handle) throws IOException;
-}
diff --git a/core/java/android/bluetooth/RfcommSocket.java b/core/java/android/bluetooth/RfcommSocket.java
deleted file mode 100644
index a33263f..0000000
--- a/core/java/android/bluetooth/RfcommSocket.java
+++ /dev/null
@@ -1,674 +0,0 @@
-/*
- * 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.
- */
-
-package android.bluetooth;
-
-import java.io.IOException;
-import java.io.FileOutputStream;
-import java.io.FileInputStream;
-import java.io.OutputStream;
-import java.io.InputStream;
-import java.io.FileDescriptor;
-
-/**
- * The Android Bluetooth API is not finalized, and *will* change. Use at your
- * own risk.
- *
- * This class implements an API to the Bluetooth RFCOMM layer. An RFCOMM socket
- * is similar to a normal socket in that it takes an address and a port number.
- * The difference is of course that the address is a Bluetooth-device address,
- * and the port number is an RFCOMM channel. The API allows for the
- * establishment of listening sockets via methods
- * {@link #bind(String, int) bind}, {@link #listen(int) listen}, and
- * {@link #accept(RfcommSocket, int) accept}, as well as for the making of
- * outgoing connections with {@link #connect(String, int) connect},
- * {@link #connectAsync(String, int) connectAsync}, and
- * {@link #waitForAsyncConnect(int) waitForAsyncConnect}.
- *
- * After constructing a socket, you need to {@link #create() create} it and then
- * {@link #destroy() destroy} it when you are done using it. Both
- * {@link #create() create} and {@link #accept(RfcommSocket, int) accept} return
- * a {@link java.io.FileDescriptor FileDescriptor} for the actual data.
- * Alternatively, you may call {@link #getInputStream() getInputStream} and
- * {@link #getOutputStream() getOutputStream} to retrieve the respective streams
- * without going through the FileDescriptor.
- *
- * @hide
- */
-public class RfcommSocket {
-
- /**
- * Used by the native implementation of the class.
- */
- private int mNativeData;
-
- /**
- * Used by the native implementation of the class.
- */
- private int mPort;
-
- /**
- * Used by the native implementation of the class.
- */
- private String mAddress;
-
- /**
- * We save the return value of {@link #create() create} and
- * {@link #accept(RfcommSocket,int) accept} in this variable, and use it to
- * retrieve the I/O streams.
- */
- private FileDescriptor mFd;
-
- /**
- * After a call to {@link #waitForAsyncConnect(int) waitForAsyncConnect},
- * if the return value is zero, then, the the remaining time left to wait is
- * written into this variable (by the native implementation). It is possible
- * that {@link #waitForAsyncConnect(int) waitForAsyncConnect} returns before
- * the user-specified timeout expires, which is why we save the remaining
- * time in this member variable for the user to retrieve by calling method
- * {@link #getRemainingAsyncConnectWaitingTimeMs() getRemainingAsyncConnectWaitingTimeMs}.
- */
- private int mTimeoutRemainingMs;
-
- /**
- * Set to true when an asynchronous (nonblocking) connect is in progress.
- * {@see #connectAsync(String,int)}.
- */
- private boolean mIsConnecting;
-
- /**
- * Set to true after a successful call to {@link #bind(String,int) bind} and
- * used for error checking in {@link #listen(int) listen}. Reset to false
- * on {@link #destroy() destroy}.
- */
- private boolean mIsBound = false;
-
- /**
- * Set to true after a successful call to {@link #listen(int) listen} and
- * used for error checking in {@link #accept(RfcommSocket,int) accept}.
- * Reset to false on {@link #destroy() destroy}.
- */
- private boolean mIsListening = false;
-
- /**
- * Used to store the remaining time after an accept with a non-negative
- * timeout returns unsuccessfully. It is possible that a blocking
- * {@link #accept(int) accept} may wait for less than the time specified by
- * the user, which is why we store the remainder in this member variable for
- * it to be retrieved with method
- * {@link #getRemainingAcceptWaitingTimeMs() getRemainingAcceptWaitingTimeMs}.
- */
- private int mAcceptTimeoutRemainingMs;
-
- /**
- * Maintained by {@link #getInputStream() getInputStream}.
- */
- protected FileInputStream mInputStream;
-
- /**
- * Maintained by {@link #getOutputStream() getOutputStream}.
- */
- protected FileOutputStream mOutputStream;
-
- private native void initializeNativeDataNative();
-
- /**
- * Constructor.
- */
- public RfcommSocket() {
- initializeNativeDataNative();
- }
-
- private native void cleanupNativeDataNative();
-
- /**
- * Called by the GC to clean up the native data that we set up when we
- * construct the object.
- */
- protected void finalize() throws Throwable {
- try {
- cleanupNativeDataNative();
- } finally {
- super.finalize();
- }
- }
-
- private native static void classInitNative();
-
- static {
- classInitNative();
- }
-
- /**
- * Creates a socket. You need to call this method before performing any
- * other operation on a socket.
- *
- * @return FileDescriptor for the data stream.
- * @throws IOException
- * @see #destroy()
- */
- public FileDescriptor create() throws IOException {
- if (mFd == null) {
- mFd = createNative();
- }
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- return mFd;
- }
-
- private native FileDescriptor createNative();
-
- /**
- * Destroys a socket created by {@link #create() create}. Call this
- * function when you no longer use the socket in order to release the
- * underlying OS resources.
- *
- * @see #create()
- */
- public void destroy() {
- synchronized (this) {
- destroyNative();
- mFd = null;
- mIsBound = false;
- mIsListening = false;
- }
- }
-
- private native void destroyNative();
-
- /**
- * Returns the {@link java.io.FileDescriptor FileDescriptor} of the socket.
- *
- * @return the FileDescriptor
- * @throws IOException
- * when the socket has not been {@link #create() created}.
- */
- public FileDescriptor getFileDescriptor() throws IOException {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- return mFd;
- }
-
- /**
- * Retrieves the input stream from the socket. Alternatively, you can do
- * that from the FileDescriptor returned by {@link #create() create} or
- * {@link #accept(RfcommSocket, int) accept}.
- *
- * @return InputStream
- * @throws IOException
- * if you have not called {@link #create() create} on the
- * socket.
- */
- public InputStream getInputStream() throws IOException {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
-
- synchronized (this) {
- if (mInputStream == null) {
- mInputStream = new FileInputStream(mFd);
- }
-
- return mInputStream;
- }
- }
-
- /**
- * Retrieves the output stream from the socket. Alternatively, you can do
- * that from the FileDescriptor returned by {@link #create() create} or
- * {@link #accept(RfcommSocket, int) accept}.
- *
- * @return OutputStream
- * @throws IOException
- * if you have not called {@link #create() create} on the
- * socket.
- */
- public OutputStream getOutputStream() throws IOException {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
-
- synchronized (this) {
- if (mOutputStream == null) {
- mOutputStream = new FileOutputStream(mFd);
- }
-
- return mOutputStream;
- }
- }
-
- /**
- * Starts a blocking connect to a remote RFCOMM socket. It takes the address
- * of a device and the RFCOMM channel (port) to which to connect.
- *
- * @param address
- * is the Bluetooth address of the remote device.
- * @param port
- * is the RFCOMM channel
- * @return true on success, false on failure
- * @throws IOException
- * if {@link #create() create} has not been called.
- * @see #connectAsync(String, int)
- */
- public boolean connect(String address, int port) throws IOException {
- synchronized (this) {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- return connectNative(address, port);
- }
- }
-
- private native boolean connectNative(String address, int port);
-
- /**
- * Starts an asynchronous (nonblocking) connect to a remote RFCOMM socket.
- * It takes the address of the device to connect to, as well as the RFCOMM
- * channel (port). On successful return (return value is true), you need to
- * call method {@link #waitForAsyncConnect(int) waitForAsyncConnect} to
- * block for up to a specified number of milliseconds while waiting for the
- * asyncronous connect to complete.
- *
- * @param address
- * of remote device
- * @param port
- * the RFCOMM channel
- * @return true when the asynchronous connect has successfully started,
- * false if there was an error.
- * @throws IOException
- * is you have not called {@link #create() create}
- * @see #waitForAsyncConnect(int)
- * @see #getRemainingAsyncConnectWaitingTimeMs()
- * @see #connect(String, int)
- */
- public boolean connectAsync(String address, int port) throws IOException {
- synchronized (this) {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- mIsConnecting = connectAsyncNative(address, port);
- return mIsConnecting;
- }
- }
-
- private native boolean connectAsyncNative(String address, int port);
-
- /**
- * Interrupts an asynchronous connect in progress. This method does nothing
- * when there is no asynchronous connect in progress.
- *
- * @throws IOException
- * if you have not called {@link #create() create}.
- * @see #connectAsync(String, int)
- */
- public void interruptAsyncConnect() throws IOException {
- synchronized (this) {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- if (mIsConnecting) {
- mIsConnecting = !interruptAsyncConnectNative();
- }
- }
- }
-
- private native boolean interruptAsyncConnectNative();
-
- /**
- * Tells you whether there is an asynchronous connect in progress. This
- * method returns an undefined value when there is a synchronous connect in
- * progress.
- *
- * @return true if there is an asyc connect in progress, false otherwise
- * @see #connectAsync(String, int)
- */
- public boolean isConnecting() {
- return mIsConnecting;
- }
-
- /**
- * Blocks for a specified amount of milliseconds while waiting for an
- * asynchronous connect to complete. Returns an integer value to indicate
- * one of the following: the connect succeeded, the connect is still in
- * progress, or the connect failed. It is possible for this method to block
- * for less than the time specified by the user, and still return zero
- * (i.e., async connect is still in progress.) For this reason, if the
- * return value is zero, you need to call method
- * {@link #getRemainingAsyncConnectWaitingTimeMs() getRemainingAsyncConnectWaitingTimeMs}
- * to retrieve the remaining time.
- *
- * @param timeoutMs
- * the time to block while waiting for the async connect to
- * complete.
- * @return a positive value if the connect succeeds; zero, if the connect is
- * still in progress, and a negative value if the connect failed.
- *
- * @throws IOException
- * @see #getRemainingAsyncConnectWaitingTimeMs()
- * @see #connectAsync(String, int)
- */
- public int waitForAsyncConnect(int timeoutMs) throws IOException {
- synchronized (this) {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- int ret = waitForAsyncConnectNative(timeoutMs);
- if (ret != 0) {
- mIsConnecting = false;
- }
- return ret;
- }
- }
-
- private native int waitForAsyncConnectNative(int timeoutMs);
-
- /**
- * Returns the number of milliseconds left to wait after the last call to
- * {@link #waitForAsyncConnect(int) waitForAsyncConnect}.
- *
- * It is possible that waitForAsyncConnect() waits for less than the time
- * specified by the user, and still returns zero (i.e., async connect is
- * still in progress.) For this reason, if the return value is zero, you
- * need to call this method to retrieve the remaining time before you call
- * waitForAsyncConnect again.
- *
- * @return the remaining timeout in milliseconds.
- * @see #waitForAsyncConnect(int)
- * @see #connectAsync(String, int)
- */
- public int getRemainingAsyncConnectWaitingTimeMs() {
- return mTimeoutRemainingMs;
- }
-
- /**
- * Shuts down both directions on a socket.
- *
- * @return true on success, false on failure; if the return value is false,
- * the socket might be left in a patially shut-down state (i.e. one
- * direction is shut down, but the other is still open.) In this
- * case, you should {@link #destroy() destroy} and then
- * {@link #create() create} the socket again.
- * @throws IOException
- * is you have not caled {@link #create() create}.
- * @see #shutdownInput()
- * @see #shutdownOutput()
- */
- public boolean shutdown() throws IOException {
- synchronized (this) {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- if (shutdownNative(true)) {
- return shutdownNative(false);
- }
-
- return false;
- }
- }
-
- /**
- * Shuts down the input stream of the socket, but leaves the output stream
- * in its current state.
- *
- * @return true on success, false on failure
- * @throws IOException
- * is you have not called {@link #create() create}
- * @see #shutdown()
- * @see #shutdownOutput()
- */
- public boolean shutdownInput() throws IOException {
- synchronized (this) {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- return shutdownNative(true);
- }
- }
-
- /**
- * Shut down the output stream of the socket, but leaves the input stream in
- * its current state.
- *
- * @return true on success, false on failure
- * @throws IOException
- * is you have not called {@link #create() create}
- * @see #shutdown()
- * @see #shutdownInput()
- */
- public boolean shutdownOutput() throws IOException {
- synchronized (this) {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- return shutdownNative(false);
- }
- }
-
- private native boolean shutdownNative(boolean shutdownInput);
-
- /**
- * Tells you whether a socket is connected to another socket. This could be
- * for input or output or both.
- *
- * @return true if connected, false otherwise.
- * @see #isInputConnected()
- * @see #isOutputConnected()
- */
- public boolean isConnected() {
- return isConnectedNative() > 0;
- }
-
- /**
- * Determines whether input is connected (i.e., whether you can receive data
- * on this socket.)
- *
- * @return true if input is connected, false otherwise.
- * @see #isConnected()
- * @see #isOutputConnected()
- */
- public boolean isInputConnected() {
- return (isConnectedNative() & 1) != 0;
- }
-
- /**
- * Determines whether output is connected (i.e., whether you can send data
- * on this socket.)
- *
- * @return true if output is connected, false otherwise.
- * @see #isConnected()
- * @see #isInputConnected()
- */
- public boolean isOutputConnected() {
- return (isConnectedNative() & 2) != 0;
- }
-
- private native int isConnectedNative();
-
- /**
- * Binds a listening socket to the local device, or a non-listening socket
- * to a remote device. The port is automatically selected as the first
- * available port in the range 12 to 30.
- *
- * NOTE: Currently we ignore the device parameter and always bind the socket
- * to the local device, assuming that it is a listening socket.
- *
- * TODO: Use bind(0) in native code to have the kernel select an unused
- * port.
- *
- * @param device
- * Bluetooth address of device to bind to (currently ignored).
- * @return true on success, false on failure
- * @throws IOException
- * if you have not called {@link #create() create}
- * @see #listen(int)
- * @see #accept(RfcommSocket,int)
- */
- public boolean bind(String device) throws IOException {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- for (int port = 12; port <= 30; port++) {
- if (bindNative(device, port)) {
- mIsBound = true;
- return true;
- }
- }
- mIsBound = false;
- return false;
- }
-
- /**
- * Binds a listening socket to the local device, or a non-listening socket
- * to a remote device.
- *
- * NOTE: Currently we ignore the device parameter and always bind the socket
- * to the local device, assuming that it is a listening socket.
- *
- * @param device
- * Bluetooth address of device to bind to (currently ignored).
- * @param port
- * RFCOMM channel to bind socket to.
- * @return true on success, false on failure
- * @throws IOException
- * if you have not called {@link #create() create}
- * @see #listen(int)
- * @see #accept(RfcommSocket,int)
- */
- public boolean bind(String device, int port) throws IOException {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- mIsBound = bindNative(device, port);
- return mIsBound;
- }
-
- private native boolean bindNative(String device, int port);
-
- /**
- * Starts listening for incoming connections on this socket, after it has
- * been bound to an address and RFCOMM channel with
- * {@link #bind(String,int) bind}.
- *
- * @param backlog
- * the number of pending incoming connections to queue for
- * {@link #accept(RfcommSocket, int) accept}.
- * @return true on success, false on failure
- * @throws IOException
- * if you have not called {@link #create() create} or if the
- * socket has not been bound to a device and RFCOMM channel.
- */
- public boolean listen(int backlog) throws IOException {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- if (!mIsBound) {
- throw new IOException("socket not bound");
- }
- mIsListening = listenNative(backlog);
- return mIsListening;
- }
-
- private native boolean listenNative(int backlog);
-
- /**
- * Accepts incoming-connection requests for a listening socket bound to an
- * RFCOMM channel. The user may provide a time to wait for an incoming
- * connection.
- *
- * Note that this method may return null (i.e., no incoming connection)
- * before the user-specified timeout expires. For this reason, on a null
- * return value, you need to call
- * {@link #getRemainingAcceptWaitingTimeMs() getRemainingAcceptWaitingTimeMs}
- * in order to see how much time is left to wait, before you call this
- * method again.
- *
- * @param newSock
- * is set to the new socket that is created as a result of a
- * successful accept.
- * @param timeoutMs
- * time (in milliseconds) to block while waiting to an
- * incoming-connection request. A negative value is an infinite
- * wait.
- * @return FileDescriptor of newSock on success, null on failure. Failure
- * occurs if the timeout expires without a successful connect.
- * @throws IOException
- * if the socket has not been {@link #create() create}ed, is
- * not bound, or is not a listening socket.
- * @see #bind(String, int)
- * @see #listen(int)
- * @see #getRemainingAcceptWaitingTimeMs()
- */
- public FileDescriptor accept(RfcommSocket newSock, int timeoutMs)
- throws IOException {
- synchronized (newSock) {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- if (mIsListening == false) {
- throw new IOException("not listening on socket");
- }
- newSock.mFd = acceptNative(newSock, timeoutMs);
- return newSock.mFd;
- }
- }
-
- /**
- * Returns the number of milliseconds left to wait after the last call to
- * {@link #accept(RfcommSocket, int) accept}.
- *
- * Since accept() may return null (i.e., no incoming connection) before the
- * user-specified timeout expires, you need to call this method in order to
- * see how much time is left to wait, and wait for that amount of time
- * before you call accept again.
- *
- * @return the remaining time, in milliseconds.
- */
- public int getRemainingAcceptWaitingTimeMs() {
- return mAcceptTimeoutRemainingMs;
- }
-
- private native FileDescriptor acceptNative(RfcommSocket newSock,
- int timeoutMs);
-
- /**
- * Get the port (rfcomm channel) associated with this socket.
- *
- * This is only valid if the port has been set via a successful call to
- * {@link #bind(String, int)}, {@link #connect(String, int)}
- * or {@link #connectAsync(String, int)}. This can be checked
- * with {@link #isListening()} and {@link #isConnected()}.
- * @return Port (rfcomm channel)
- */
- public int getPort() throws IOException {
- if (mFd == null) {
- throw new IOException("socket not created");
- }
- if (!mIsListening && !isConnected()) {
- throw new IOException("not listening or connected on socket");
- }
- return mPort;
- }
-
- /**
- * Return true if this socket is listening ({@link #listen(int)}
- * has been called successfully).
- */
- public boolean isListening() {
- return mIsListening;
- }
-}
diff --git a/core/java/android/content/AbstractCursorEntityIterator.java b/core/java/android/content/AbstractCursorEntityIterator.java
new file mode 100644
index 0000000..bf3c4de
--- /dev/null
+++ b/core/java/android/content/AbstractCursorEntityIterator.java
@@ -0,0 +1,112 @@
+package android.content;
+
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.RemoteException;
+
+/**
+ * An abstract class that makes it easy to implement an EntityIterator over a cursor.
+ * The user must implement {@link #newEntityFromCursorLocked}, which runs inside of a
+ * database transaction.
+ */
+public abstract class AbstractCursorEntityIterator implements EntityIterator {
+ private final Cursor mEntityCursor;
+ private final SQLiteDatabase mDb;
+ private volatile Entity mNextEntity;
+ private volatile boolean mIsClosed;
+
+ public AbstractCursorEntityIterator(SQLiteDatabase db, Cursor entityCursor) {
+ mEntityCursor = entityCursor;
+ mDb = db;
+ mNextEntity = null;
+ mIsClosed = false;
+ }
+
+ /**
+ * If there are entries left in the cursor then advance the cursor and use the new row to
+ * populate mNextEntity. If the cursor is at the end or if advancing it causes the cursor
+ * to become at the end then set mEntityCursor to null. If newEntityFromCursor returns null
+ * then continue advancing until it either returns a non-null Entity or the cursor reaches
+ * the end.
+ */
+ private void fillEntityIfAvailable() {
+ while (mNextEntity == null) {
+ if (!mEntityCursor.moveToNext()) {
+ // the cursor is at then end, bail out
+ return;
+ }
+ // This may return null if newEntityFromCursor is not able to create an entity
+ // from the current cursor position. In that case this method will loop and try
+ // the next cursor position
+ mNextEntity = newEntityFromCursorLocked(mEntityCursor);
+ }
+ mDb.beginTransaction();
+ try {
+ int position = mEntityCursor.getPosition();
+ mNextEntity = newEntityFromCursorLocked(mEntityCursor);
+ int newPosition = mEntityCursor.getPosition();
+ if (newPosition != position) {
+ throw new IllegalStateException("the cursor position changed during the call to"
+ + "newEntityFromCursorLocked, from " + position + " to " + newPosition);
+ }
+ } finally {
+ mDb.endTransaction();
+ }
+ }
+
+ /**
+ * Checks if there are more Entities accessible via this iterator. This may not be called
+ * if the iterator is already closed.
+ * @return true if the call to next() will return an Entity.
+ */
+ public boolean hasNext() {
+ if (mIsClosed) {
+ throw new IllegalStateException("calling hasNext() when the iterator is closed");
+ }
+ fillEntityIfAvailable();
+ return mNextEntity != null;
+ }
+
+ /**
+ * Returns the next Entity that is accessible via this iterator. This may not be called
+ * if the iterator is already closed.
+ * @return the next Entity that is accessible via this iterator
+ */
+ public Entity next() {
+ if (mIsClosed) {
+ throw new IllegalStateException("calling next() when the iterator is closed");
+ }
+ if (!hasNext()) {
+ throw new IllegalStateException("you may only call next() if hasNext() is true");
+ }
+
+ try {
+ return mNextEntity;
+ } finally {
+ mNextEntity = null;
+ }
+ }
+
+ /**
+ * Closes this iterator making it invalid. If is invalid for the user to call any public
+ * method on the iterator once it has been closed.
+ */
+ public void close() {
+ if (mIsClosed) {
+ throw new IllegalStateException("closing when already closed");
+ }
+ mIsClosed = true;
+ mEntityCursor.close();
+ }
+
+ /**
+ * Returns a new Entity from the current cursor position. This is called from within a
+ * database transaction. If a new entity cannot be created from this cursor position (e.g.
+ * if the row that is referred to no longer exists) then this may return null. The cursor
+ * is guaranteed to be pointing to a valid row when this call is made. The implementation
+ * of newEntityFromCursorLocked is not allowed to change the position of the cursor.
+ * @param cursor from where to read the data for the Entity
+ * @return an Entity that corresponds to the current cursor position or null
+ */
+ public abstract Entity newEntityFromCursorLocked(Cursor cursor);
+}
diff --git a/core/java/android/content/AbstractSyncableContentProvider.java b/core/java/android/content/AbstractSyncableContentProvider.java
index 249d9ba..e628dcd 100644
--- a/core/java/android/content/AbstractSyncableContentProvider.java
+++ b/core/java/android/content/AbstractSyncableContentProvider.java
@@ -4,8 +4,9 @@ import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase;
import android.database.Cursor;
import android.net.Uri;
-import android.accounts.AccountMonitor;
-import android.accounts.AccountMonitorListener;
+import android.accounts.OnAccountsUpdatedListener;
+import android.accounts.Account;
+import android.accounts.AccountManager;
import android.provider.SyncConstValue;
import android.util.Config;
import android.util.Log;
@@ -14,9 +15,12 @@ import android.text.TextUtils;
import java.util.Collections;
import java.util.Map;
-import java.util.HashMap;
import java.util.Vector;
import java.util.ArrayList;
+import java.util.Set;
+import java.util.HashSet;
+
+import com.google.android.collect.Maps;
/**
* A specialization of the ContentProvider that centralizes functionality
@@ -32,26 +36,30 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
private final String mDatabaseName;
private final int mDatabaseVersion;
private final Uri mContentUri;
- private AccountMonitor mAccountMonitor;
/** the account set in the last call to onSyncStart() */
- private String mSyncingAccount;
+ private Account mSyncingAccount;
private SyncStateContentProviderHelper mSyncState = null;
- private static final String[] sAccountProjection = new String[] {SyncConstValue._SYNC_ACCOUNT};
+ private static final String[] sAccountProjection =
+ new String[] {SyncConstValue._SYNC_ACCOUNT, SyncConstValue._SYNC_ACCOUNT_TYPE};
private boolean mIsTemporary;
private AbstractTableMerger mCurrentMerger = null;
private boolean mIsMergeCancelled = false;
- private static final String SYNC_ACCOUNT_WHERE_CLAUSE = SyncConstValue._SYNC_ACCOUNT + "=?";
+ private static final String SYNC_ACCOUNT_WHERE_CLAUSE =
+ SyncConstValue._SYNC_ACCOUNT + "=? AND " + SyncConstValue._SYNC_ACCOUNT_TYPE + "=?";
protected boolean isTemporary() {
return mIsTemporary;
}
+ private final ThreadLocal<Boolean> mApplyingBatch = new ThreadLocal<Boolean>();
+ private final ThreadLocal<Set<Uri>> mPendingBatchNotifications = new ThreadLocal<Set<Uri>>();
+
/**
* Indicates whether or not this ContentProvider contains a full
* set of data or just diffs. This knowledge comes in handy when
@@ -150,19 +158,19 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
mOpenHelper = new AbstractSyncableContentProvider.DatabaseHelper(getContext(),
mDatabaseName);
mSyncState = new SyncStateContentProviderHelper(mOpenHelper);
-
- AccountMonitorListener listener = new AccountMonitorListener() {
- public void onAccountsUpdated(String[] accounts) {
- // Some providers override onAccountsChanged(); give them a database to work with.
- mDb = mOpenHelper.getWritableDatabase();
- onAccountsChanged(accounts);
- TempProviderSyncAdapter syncAdapter = (TempProviderSyncAdapter)getSyncAdapter();
- if (syncAdapter != null) {
- syncAdapter.onAccountsChanged(accounts);
- }
- }
- };
- mAccountMonitor = new AccountMonitor(getContext(), listener);
+ AccountManager.get(getContext()).addOnAccountsUpdatedListener(
+ new OnAccountsUpdatedListener() {
+ public void onAccountsUpdated(Account[] accounts) {
+ // Some providers override onAccountsChanged(); give them a database to
+ // work with.
+ mDb = mOpenHelper.getWritableDatabase();
+ onAccountsChanged(accounts);
+ TempProviderSyncAdapter syncAdapter = getTempProviderSyncAdapter();
+ if (syncAdapter != null) {
+ syncAdapter.onAccountsChanged(accounts);
+ }
+ }
+ }, null /* handler */, true /* updateImmediately */);
return true;
}
@@ -236,147 +244,117 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
return Collections.emptyList();
}
- /**
- * <p>
- * Call mOpenHelper.getWritableDatabase() and mDb.beginTransaction().
- * {@link #endTransaction} MUST be called after calling this method.
- * Those methods should be used like this:
- * </p>
- *
- * <pre class="prettyprint">
- * boolean successful = false;
- * beginTransaction();
- * try {
- * // Do something related to mDb
- * successful = true;
- * return ret;
- * } finally {
- * endTransaction(successful);
- * }
- * </pre>
- *
- * @hide This method is dangerous from the view of database manipulation, though using
- * this makes batch insertion/update/delete much faster.
- */
- public final void beginTransaction() {
+ @Override
+ public final int update(final Uri url, final ContentValues values,
+ final String selection, final String[] selectionArgs) {
mDb = mOpenHelper.getWritableDatabase();
- mDb.beginTransaction();
- }
-
- /**
- * <p>
- * Call mDb.endTransaction(). If successful is true, try to call
- * mDb.setTransactionSuccessful() before calling mDb.endTransaction().
- * This method MUST be used with {@link #beginTransaction()}.
- * </p>
- *
- * @hide This method is dangerous from the view of database manipulation, though using
- * this makes batch insertion/update/delete much faster.
- */
- public final void endTransaction(boolean successful) {
+ final boolean notApplyingBatch = !applyingBatch();
+ if (notApplyingBatch) {
+ mDb.beginTransaction();
+ }
try {
- if (successful) {
- // setTransactionSuccessful() must be called just once during opening the
- // transaction.
- mDb.setTransactionSuccessful();
+ if (isTemporary() && mSyncState.matches(url)) {
+ int numRows = mSyncState.asContentProvider().update(
+ url, values, selection, selectionArgs);
+ if (notApplyingBatch) {
+ mDb.setTransactionSuccessful();
+ }
+ return numRows;
}
- } finally {
- mDb.endTransaction();
- }
- }
- @Override
- public final int update(final Uri uri, final ContentValues values,
- final String selection, final String[] selectionArgs) {
- boolean successful = false;
- beginTransaction();
- try {
- int ret = nonTransactionalUpdate(uri, values, selection, selectionArgs);
- successful = true;
- return ret;
+ int result = updateInternal(url, values, selection, selectionArgs);
+ if (notApplyingBatch) {
+ mDb.setTransactionSuccessful();
+ }
+ if (!isTemporary() && result > 0) {
+ if (notApplyingBatch) {
+ getContext().getContentResolver().notifyChange(url, null /* observer */,
+ changeRequiresLocalSync(url));
+ } else {
+ mPendingBatchNotifications.get().add(url);
+ }
+ }
+ return result;
} finally {
- endTransaction(successful);
- }
- }
-
- /**
- * @hide
- */
- public final int nonTransactionalUpdate(final Uri uri, final ContentValues values,
- final String selection, final String[] selectionArgs) {
- if (isTemporary() && mSyncState.matches(uri)) {
- int numRows = mSyncState.asContentProvider().update(
- uri, values, selection, selectionArgs);
- return numRows;
- }
-
- int result = updateInternal(uri, values, selection, selectionArgs);
- if (!isTemporary() && result > 0) {
- getContext().getContentResolver().notifyChange(uri, null /* observer */,
- changeRequiresLocalSync(uri));
+ if (notApplyingBatch) {
+ mDb.endTransaction();
+ }
}
-
- return result;
}
@Override
- public final int delete(final Uri uri, final String selection,
+ public final int delete(final Uri url, final String selection,
final String[] selectionArgs) {
- boolean successful = false;
- beginTransaction();
+ mDb = mOpenHelper.getWritableDatabase();
+ final boolean notApplyingBatch = !applyingBatch();
+ if (notApplyingBatch) {
+ mDb.beginTransaction();
+ }
try {
- int ret = nonTransactionalDelete(uri, selection, selectionArgs);
- successful = true;
- return ret;
+ if (isTemporary() && mSyncState.matches(url)) {
+ int numRows = mSyncState.asContentProvider().delete(url, selection, selectionArgs);
+ if (notApplyingBatch) {
+ mDb.setTransactionSuccessful();
+ }
+ return numRows;
+ }
+ int result = deleteInternal(url, selection, selectionArgs);
+ if (notApplyingBatch) {
+ mDb.setTransactionSuccessful();
+ }
+ if (!isTemporary() && result > 0) {
+ if (notApplyingBatch) {
+ getContext().getContentResolver().notifyChange(url, null /* observer */,
+ changeRequiresLocalSync(url));
+ } else {
+ mPendingBatchNotifications.get().add(url);
+ }
+ }
+ return result;
} finally {
- endTransaction(successful);
+ if (notApplyingBatch) {
+ mDb.endTransaction();
+ }
}
}
- /**
- * @hide
- */
- public final int nonTransactionalDelete(final Uri uri, final String selection,
- final String[] selectionArgs) {
- if (isTemporary() && mSyncState.matches(uri)) {
- int numRows = mSyncState.asContentProvider().delete(uri, selection, selectionArgs);
- return numRows;
- }
- int result = deleteInternal(uri, selection, selectionArgs);
- if (!isTemporary() && result > 0) {
- getContext().getContentResolver().notifyChange(uri, null /* observer */,
- changeRequiresLocalSync(uri));
- }
- return result;
+ private boolean applyingBatch() {
+ return mApplyingBatch.get() != null && mApplyingBatch.get();
}
@Override
- public final Uri insert(final Uri uri, final ContentValues values) {
- boolean successful = false;
- beginTransaction();
- try {
- Uri ret = nonTransactionalInsert(uri, values);
- successful = true;
- return ret;
- } finally {
- endTransaction(successful);
+ public final Uri insert(final Uri url, final ContentValues values) {
+ mDb = mOpenHelper.getWritableDatabase();
+ final boolean notApplyingBatch = !applyingBatch();
+ if (notApplyingBatch) {
+ mDb.beginTransaction();
}
- }
-
- /**
- * @hide
- */
- public final Uri nonTransactionalInsert(final Uri uri, final ContentValues values) {
- if (isTemporary() && mSyncState.matches(uri)) {
- Uri result = mSyncState.asContentProvider().insert(uri, values);
+ try {
+ if (isTemporary() && mSyncState.matches(url)) {
+ Uri result = mSyncState.asContentProvider().insert(url, values);
+ if (notApplyingBatch) {
+ mDb.setTransactionSuccessful();
+ }
+ return result;
+ }
+ Uri result = insertInternal(url, values);
+ if (notApplyingBatch) {
+ mDb.setTransactionSuccessful();
+ }
+ if (!isTemporary() && result != null) {
+ if (notApplyingBatch) {
+ getContext().getContentResolver().notifyChange(url, null /* observer */,
+ changeRequiresLocalSync(url));
+ } else {
+ mPendingBatchNotifications.get().add(url);
+ }
+ }
return result;
+ } finally {
+ if (notApplyingBatch) {
+ mDb.endTransaction();
+ }
}
- Uri result = insertInternal(uri, values);
- if (!isTemporary() && result != null) {
- getContext().getContentResolver().notifyChange(uri, null /* observer */,
- changeRequiresLocalSync(uri));
- }
- return result;
}
@Override
@@ -411,6 +389,92 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
}
/**
+ * <p>
+ * Start batch transaction. {@link #endTransaction} MUST be called after
+ * calling this method. Those methods should be used like this:
+ * </p>
+ *
+ * <pre class="prettyprint">
+ * boolean successful = false;
+ * beginBatch()
+ * try {
+ * // Do something related to mDb
+ * successful = true;
+ * return ret;
+ * } finally {
+ * endBatch(successful);
+ * }
+ * </pre>
+ *
+ * @hide This method should be used only when {@link ContentProvider#applyBatch} is not enough and must be
+ * used with {@link #endBatch}.
+ * e.g. If returned value has to be used during one transaction, this method might be useful.
+ */
+ public final void beginBatch() {
+ // initialize if this is the first time this thread has applied a batch
+ if (mApplyingBatch.get() == null) {
+ mApplyingBatch.set(false);
+ mPendingBatchNotifications.set(new HashSet<Uri>());
+ }
+
+ if (applyingBatch()) {
+ throw new IllegalStateException(
+ "applyBatch is not reentrant but mApplyingBatch is already set");
+ }
+ SQLiteDatabase db = getDatabase();
+ db.beginTransaction();
+ boolean successful = false;
+ try {
+ mApplyingBatch.set(true);
+ successful = true;
+ } finally {
+ if (!successful) {
+ // Something unexpected happened. We must call endTransaction() at least.
+ db.endTransaction();
+ }
+ }
+ }
+
+ /**
+ * <p>
+ * Finish batch transaction. If "successful" is true, try to call
+ * mDb.setTransactionSuccessful() before calling mDb.endTransaction().
+ * This method MUST be used with {@link #beginBatch()}.
+ * </p>
+ *
+ * @hide This method must be used with {@link #beginTransaction}
+ */
+ public final void endBatch(boolean successful) {
+ try {
+ if (successful) {
+ // setTransactionSuccessful() must be called just once during opening the
+ // transaction.
+ mDb.setTransactionSuccessful();
+ }
+ } finally {
+ mApplyingBatch.set(false);
+ getDatabase().endTransaction();
+ for (Uri url : mPendingBatchNotifications.get()) {
+ getContext().getContentResolver().notifyChange(url, null /* observer */,
+ changeRequiresLocalSync(url));
+ }
+ }
+ }
+
+ public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
+ throws OperationApplicationException {
+ boolean successful = false;
+ beginBatch();
+ try {
+ ContentProviderResult[] results = super.applyBatch(operations);
+ successful = true;
+ return results;
+ } finally {
+ endBatch(successful);
+ }
+ }
+
+ /**
* Check if changes to this URI can be syncable changes.
* @param uri the URI of the resource that was changed
* @return true if changes to this URI can be syncable changes, false otherwise
@@ -437,8 +501,8 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
* @param context the sync context for the operation
* @param account
*/
- public void onSyncStart(SyncContext context, String account) {
- if (TextUtils.isEmpty(account)) {
+ public void onSyncStart(SyncContext context, Account account) {
+ if (account == null) {
throw new IllegalArgumentException("you passed in an empty account");
}
mSyncingAccount = account;
@@ -457,7 +521,7 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
* The account of the most recent call to onSyncStart()
* @return the account
*/
- public String getSyncingAccount() {
+ public Account getSyncingAccount() {
return mSyncingAccount;
}
@@ -568,12 +632,11 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
* Make sure that there are no entries for accounts that no longer exist
* @param accountsArray the array of currently-existing accounts
*/
- protected void onAccountsChanged(String[] accountsArray) {
- Map<String, Boolean> accounts = new HashMap<String, Boolean>();
- for (String account : accountsArray) {
+ protected void onAccountsChanged(Account[] accountsArray) {
+ Map<Account, Boolean> accounts = Maps.newHashMap();
+ for (Account account : accountsArray) {
accounts.put(account, false);
}
- accounts.put(SyncConstValue.NON_SYNCABLE_ACCOUNT, false);
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
Map<String, String> tableMap = db.getSyncedTables();
@@ -585,8 +648,7 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
try {
mSyncState.onAccountsChanged(accountsArray);
for (String table : tables) {
- deleteRowsForRemovedAccounts(accounts, table,
- SyncConstValue._SYNC_ACCOUNT);
+ deleteRowsForRemovedAccounts(accounts, table);
}
db.setTransactionSuccessful();
} finally {
@@ -601,23 +663,23 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
*
* @param accounts a map of existing accounts
* @param table the table to delete from
- * @param accountColumnName the name of the column that is expected
- * to hold the account.
*/
- protected void deleteRowsForRemovedAccounts(Map<String, Boolean> accounts,
- String table, String accountColumnName) {
+ protected void deleteRowsForRemovedAccounts(Map<Account, Boolean> accounts, String table) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
Cursor c = db.query(table, sAccountProjection, null, null,
- accountColumnName, null, null);
+ "_sync_account, _sync_account_type", null, null);
try {
while (c.moveToNext()) {
- String account = c.getString(0);
- if (TextUtils.isEmpty(account)) {
+ String accountName = c.getString(0);
+ String accountType = c.getString(1);
+ if (TextUtils.isEmpty(accountName)) {
continue;
}
+ Account account = new Account(accountName, accountType);
if (!accounts.containsKey(account)) {
int numDeleted;
- numDeleted = db.delete(table, accountColumnName + "=?", new String[]{account});
+ numDeleted = db.delete(table, "_sync_account=? AND _sync_account_type=?",
+ new String[]{account.mName, account.mType});
if (Config.LOGV) {
Log.v(TAG, "deleted " + numDeleted
+ " records from table " + table
@@ -634,7 +696,7 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
* Called when the sync system determines that this provider should no longer
* contain records for the specified account.
*/
- public void wipeAccount(String account) {
+ public void wipeAccount(Account account) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
Map<String, String> tableMap = db.getSyncedTables();
ArrayList<String> tables = new ArrayList<String>();
@@ -649,7 +711,8 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
// remove the data in the synced tables
for (String table : tables) {
- db.delete(table, SYNC_ACCOUNT_WHERE_CLAUSE, new String[]{account});
+ db.delete(table, SYNC_ACCOUNT_WHERE_CLAUSE,
+ new String[]{account.mName, account.mType});
}
db.setTransactionSuccessful();
} finally {
@@ -660,14 +723,14 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
/**
* Retrieves the SyncData bytes for the given account. The byte array returned may be null.
*/
- public byte[] readSyncDataBytes(String account) {
+ public byte[] readSyncDataBytes(Account account) {
return mSyncState.readSyncDataBytes(mOpenHelper.getReadableDatabase(), account);
}
/**
* Sets the SyncData bytes for the given account. The byte array may be null.
*/
- public void writeSyncDataBytes(String account, byte[] data) {
+ public void writeSyncDataBytes(Account account, byte[] data) {
mSyncState.writeSyncDataBytes(mOpenHelper.getWritableDatabase(), account, data);
}
}
diff --git a/core/java/android/content/AbstractTableMerger.java b/core/java/android/content/AbstractTableMerger.java
index 94afcee..835dd91 100644
--- a/core/java/android/content/AbstractTableMerger.java
+++ b/core/java/android/content/AbstractTableMerger.java
@@ -25,6 +25,7 @@ import android.provider.BaseColumns;
import static android.provider.SyncConstValue.*;
import android.text.TextUtils;
import android.util.Log;
+import android.accounts.Account;
/**
* @hide
@@ -55,15 +56,17 @@ public abstract class AbstractTableMerger
private volatile boolean mIsMergeCancelled;
- private static final String SELECT_MARKED = _SYNC_MARK + "> 0 and " + _SYNC_ACCOUNT + "=?";
+ private static final String SELECT_MARKED = _SYNC_MARK + "> 0 and "
+ + _SYNC_ACCOUNT + "=? and " + _SYNC_ACCOUNT_TYPE + "=?";
private static final String SELECT_BY_SYNC_ID_AND_ACCOUNT =
- _SYNC_ID +"=? and " + _SYNC_ACCOUNT + "=?";
+ _SYNC_ID +"=? and " + _SYNC_ACCOUNT + "=? and " + _SYNC_ACCOUNT_TYPE + "=?";
private static final String SELECT_BY_ID = BaseColumns._ID +"=?";
// The last clause rejects events with a null _SYNC_VERSION if they've already been synced
private static final String SELECT_UNSYNCED = ""
- + _SYNC_DIRTY + " > 0 and (" + _SYNC_ACCOUNT + "=? or " + _SYNC_ACCOUNT + " is null) "
+ + _SYNC_DIRTY + " > 0 and ((" + _SYNC_ACCOUNT + "=? AND " + _SYNC_ACCOUNT_TYPE + "=?) "
+ + "or " + _SYNC_ACCOUNT + " is null) "
+ "and (" + _SYNC_VERSION + " is not null or " + _SYNC_ACCOUNT + " is null)";
public AbstractTableMerger(SQLiteDatabase database,
@@ -134,7 +137,7 @@ public abstract class AbstractTableMerger
* construct a temporary instance to hold them.
*/
public void merge(final SyncContext context,
- final String account,
+ final Account account,
final SyncableContentProvider serverDiffs,
TempProviderSyncResult result,
SyncResult syncResult, SyncableContentProvider temporaryInstanceFactory) {
@@ -157,7 +160,7 @@ public abstract class AbstractTableMerger
* @hide this is public for testing purposes only
*/
public void mergeServerDiffs(SyncContext context,
- String account, SyncableContentProvider serverDiffs, SyncResult syncResult) {
+ Account account, SyncableContentProvider serverDiffs, SyncResult syncResult) {
boolean diffsArePartial = serverDiffs.getContainsDiffs();
// mark the current rows so that we can distinguish these from new
// inserts that occur during the merge
@@ -166,339 +169,337 @@ public abstract class AbstractTableMerger
mDb.update(mDeletedTable, mSyncMarkValues, null, null);
}
- // load the local database entries, so we can merge them with the server
- final String[] accountSelectionArgs = new String[]{account};
- Cursor localCursor = mDb.query(mTable, syncDirtyProjection,
- SELECT_MARKED, accountSelectionArgs, null, null,
- mTable + "." + _SYNC_ID);
- Cursor deletedCursor;
- if (mDeletedTable != null) {
- deletedCursor = mDb.query(mDeletedTable, syncIdAndVersionProjection,
+ Cursor localCursor = null;
+ Cursor deletedCursor = null;
+ Cursor diffsCursor = null;
+ try {
+ // load the local database entries, so we can merge them with the server
+ final String[] accountSelectionArgs = new String[]{account.mName, account.mType};
+ localCursor = mDb.query(mTable, syncDirtyProjection,
SELECT_MARKED, accountSelectionArgs, null, null,
- mDeletedTable + "." + _SYNC_ID);
- } else {
- deletedCursor =
- mDb.rawQuery("select 'a' as _sync_id, 'b' as _sync_version limit 0", null);
- }
-
- // Apply updates and insertions from the server
- Cursor diffsCursor = serverDiffs.query(mTableURL,
- null, null, null, mTable + "." + _SYNC_ID);
- int deletedSyncIDColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_ID);
- int deletedSyncVersionColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_VERSION);
- int serverSyncIDColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_ID);
- int serverSyncVersionColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_VERSION);
- int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID);
-
- String lastSyncId = null;
- int diffsCount = 0;
- int localCount = 0;
- localCursor.moveToFirst();
- deletedCursor.moveToFirst();
- while (diffsCursor.moveToNext()) {
- if (mIsMergeCancelled) {
- localCursor.close();
- deletedCursor.close();
- diffsCursor.close();
- return;
- }
- mDb.yieldIfContended();
- String serverSyncId = diffsCursor.getString(serverSyncIDColumn);
- String serverSyncVersion = diffsCursor.getString(serverSyncVersionColumn);
- long localRowId = 0;
- String localSyncVersion = null;
-
- diffsCount++;
- context.setStatusText("Processing " + diffsCount + "/"
- + diffsCursor.getCount());
- if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "processing server entry " +
- diffsCount + ", " + serverSyncId);
-
- if (TRACE) {
- if (diffsCount == 10) {
- Debug.startMethodTracing("atmtrace");
- }
- if (diffsCount == 20) {
- Debug.stopMethodTracing();
- }
+ mTable + "." + _SYNC_ID);
+ if (mDeletedTable != null) {
+ deletedCursor = mDb.query(mDeletedTable, syncIdAndVersionProjection,
+ SELECT_MARKED, accountSelectionArgs, null, null,
+ mDeletedTable + "." + _SYNC_ID);
+ } else {
+ deletedCursor =
+ mDb.rawQuery("select 'a' as _sync_id, 'b' as _sync_version limit 0", null);
}
- boolean conflict = false;
- boolean update = false;
- boolean insert = false;
+ // Apply updates and insertions from the server
+ diffsCursor = serverDiffs.query(mTableURL,
+ null, null, null, mTable + "." + _SYNC_ID);
+ int deletedSyncIDColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_ID);
+ int deletedSyncVersionColumn = deletedCursor.getColumnIndexOrThrow(_SYNC_VERSION);
+ int serverSyncIDColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_ID);
+ int serverSyncVersionColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_VERSION);
+ int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID);
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "found event with serverSyncID " + serverSyncId);
- }
- if (TextUtils.isEmpty(serverSyncId)) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.e(TAG, "server entry doesn't have a serverSyncID");
+ String lastSyncId = null;
+ int diffsCount = 0;
+ int localCount = 0;
+ localCursor.moveToFirst();
+ deletedCursor.moveToFirst();
+ while (diffsCursor.moveToNext()) {
+ if (mIsMergeCancelled) {
+ return;
}
- continue;
- }
-
- // It is possible that the sync adapter wrote the same record multiple times,
- // e.g. if the same record came via multiple feeds. If this happens just ignore
- // the duplicate records.
- if (serverSyncId.equals(lastSyncId)) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "skipping record with duplicate remote server id " + lastSyncId);
+ mDb.yieldIfContended();
+ String serverSyncId = diffsCursor.getString(serverSyncIDColumn);
+ String serverSyncVersion = diffsCursor.getString(serverSyncVersionColumn);
+ long localRowId = 0;
+ String localSyncVersion = null;
+
+ diffsCount++;
+ context.setStatusText("Processing " + diffsCount + "/"
+ + diffsCursor.getCount());
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "processing server entry " +
+ diffsCount + ", " + serverSyncId);
+
+ if (TRACE) {
+ if (diffsCount == 10) {
+ Debug.startMethodTracing("atmtrace");
+ }
+ if (diffsCount == 20) {
+ Debug.stopMethodTracing();
+ }
}
- continue;
- }
- lastSyncId = serverSyncId;
- String localSyncID = null;
- boolean localSyncDirty = false;
+ boolean conflict = false;
+ boolean update = false;
+ boolean insert = false;
- while (!localCursor.isAfterLast()) {
- if (mIsMergeCancelled) {
- localCursor.deactivate();
- deletedCursor.deactivate();
- diffsCursor.deactivate();
- return;
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "found event with serverSyncID " + serverSyncId);
+ }
+ if (TextUtils.isEmpty(serverSyncId)) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.e(TAG, "server entry doesn't have a serverSyncID");
+ }
+ continue;
}
- localCount++;
- localSyncID = localCursor.getString(2);
- // If the local record doesn't have a _sync_id then
- // it is new. Ignore it for now, we will send an insert
- // the the server later.
- if (TextUtils.isEmpty(localSyncID)) {
+ // It is possible that the sync adapter wrote the same record multiple times,
+ // e.g. if the same record came via multiple feeds. If this happens just ignore
+ // the duplicate records.
+ if (serverSyncId.equals(lastSyncId)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "local record " +
- localCursor.getLong(1) +
- " has no _sync_id, ignoring");
+ Log.v(TAG, "skipping record with duplicate remote server id " + lastSyncId);
}
- localCursor.moveToNext();
- localSyncID = null;
continue;
}
+ lastSyncId = serverSyncId;
- int comp = serverSyncId.compareTo(localSyncID);
+ String localSyncID = null;
+ boolean localSyncDirty = false;
- // the local DB has a record that the server doesn't have
- if (comp > 0) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "local record " +
- localCursor.getLong(1) +
- " has _sync_id " + localSyncID +
- " that is < server _sync_id " + serverSyncId);
+ while (!localCursor.isAfterLast()) {
+ if (mIsMergeCancelled) {
+ return;
}
- if (diffsArePartial) {
- localCursor.moveToNext();
- } else {
- deleteRow(localCursor);
- if (mDeletedTable != null) {
- mDb.delete(mDeletedTable, _SYNC_ID +"=?", new String[] {localSyncID});
+ localCount++;
+ localSyncID = localCursor.getString(2);
+
+ // If the local record doesn't have a _sync_id then
+ // it is new. Ignore it for now, we will send an insert
+ // the the server later.
+ if (TextUtils.isEmpty(localSyncID)) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "local record " +
+ localCursor.getLong(1) +
+ " has no _sync_id, ignoring");
}
- syncResult.stats.numDeletes++;
- mDb.yieldIfContended();
+ localCursor.moveToNext();
+ localSyncID = null;
+ continue;
}
- localSyncID = null;
- continue;
- }
- // the server has a record that the local DB doesn't have
- if (comp < 0) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "local record " +
- localCursor.getLong(1) +
- " has _sync_id " + localSyncID +
- " that is > server _sync_id " + serverSyncId);
+ int comp = serverSyncId.compareTo(localSyncID);
+
+ // the local DB has a record that the server doesn't have
+ if (comp > 0) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "local record " +
+ localCursor.getLong(1) +
+ " has _sync_id " + localSyncID +
+ " that is < server _sync_id " + serverSyncId);
+ }
+ if (diffsArePartial) {
+ localCursor.moveToNext();
+ } else {
+ deleteRow(localCursor);
+ if (mDeletedTable != null) {
+ mDb.delete(mDeletedTable, _SYNC_ID +"=?", new String[] {localSyncID});
+ }
+ syncResult.stats.numDeletes++;
+ mDb.yieldIfContended();
+ }
+ localSyncID = null;
+ continue;
}
- localSyncID = null;
- }
- // the server and the local DB both have this record
- if (comp == 0) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "local record " +
- localCursor.getLong(1) +
- " has _sync_id " + localSyncID +
- " that matches the server _sync_id");
+ // the server has a record that the local DB doesn't have
+ if (comp < 0) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "local record " +
+ localCursor.getLong(1) +
+ " has _sync_id " + localSyncID +
+ " that is > server _sync_id " + serverSyncId);
+ }
+ localSyncID = null;
}
- localSyncDirty = localCursor.getInt(0) != 0;
- localRowId = localCursor.getLong(1);
- localSyncVersion = localCursor.getString(3);
- localCursor.moveToNext();
- }
- break;
- }
+ // the server and the local DB both have this record
+ if (comp == 0) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "local record " +
+ localCursor.getLong(1) +
+ " has _sync_id " + localSyncID +
+ " that matches the server _sync_id");
+ }
+ localSyncDirty = localCursor.getInt(0) != 0;
+ localRowId = localCursor.getLong(1);
+ localSyncVersion = localCursor.getString(3);
+ localCursor.moveToNext();
+ }
- // If this record is in the deleted table then update the server version
- // in the deleted table, if necessary, and then ignore it here.
- // We will send a deletion indication to the server down a
- // little further.
- if (findInCursor(deletedCursor, deletedSyncIDColumn, serverSyncId)) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "remote record " + serverSyncId + " is in the deleted table");
+ break;
}
- final String deletedSyncVersion = deletedCursor.getString(deletedSyncVersionColumn);
- if (!TextUtils.equals(deletedSyncVersion, serverSyncVersion)) {
+
+ // If this record is in the deleted table then update the server version
+ // in the deleted table, if necessary, and then ignore it here.
+ // We will send a deletion indication to the server down a
+ // little further.
+ if (findInCursor(deletedCursor, deletedSyncIDColumn, serverSyncId)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "setting version of deleted record " + serverSyncId + " to "
- + serverSyncVersion);
+ Log.v(TAG, "remote record " + serverSyncId + " is in the deleted table");
}
- ContentValues values = new ContentValues();
- values.put(_SYNC_VERSION, serverSyncVersion);
- mDb.update(mDeletedTable, values, "_sync_id=?", new String[]{serverSyncId});
+ final String deletedSyncVersion = deletedCursor.getString(deletedSyncVersionColumn);
+ if (!TextUtils.equals(deletedSyncVersion, serverSyncVersion)) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "setting version of deleted record " + serverSyncId + " to "
+ + serverSyncVersion);
+ }
+ ContentValues values = new ContentValues();
+ values.put(_SYNC_VERSION, serverSyncVersion);
+ mDb.update(mDeletedTable, values, "_sync_id=?", new String[]{serverSyncId});
+ }
+ continue;
}
- continue;
- }
- // If the _sync_local_id is present in the diffsCursor
- // then this record corresponds to a local record that was just
- // inserted into the server and the _sync_local_id is the row id
- // of the local record. Set these fields so that the next check
- // treats this record as an update, which will allow the
- // merger to update the record with the server's sync id
- if (!diffsCursor.isNull(serverSyncLocalIdColumn)) {
- localRowId = diffsCursor.getLong(serverSyncLocalIdColumn);
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "the remote record with sync id " + serverSyncId
- + " has a local sync id, " + localRowId);
+ // If the _sync_local_id is present in the diffsCursor
+ // then this record corresponds to a local record that was just
+ // inserted into the server and the _sync_local_id is the row id
+ // of the local record. Set these fields so that the next check
+ // treats this record as an update, which will allow the
+ // merger to update the record with the server's sync id
+ if (!diffsCursor.isNull(serverSyncLocalIdColumn)) {
+ localRowId = diffsCursor.getLong(serverSyncLocalIdColumn);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "the remote record with sync id " + serverSyncId
+ + " has a local sync id, " + localRowId);
+ }
+ localSyncID = serverSyncId;
+ localSyncDirty = false;
+ localSyncVersion = null;
}
- localSyncID = serverSyncId;
- localSyncDirty = false;
- localSyncVersion = null;
- }
- if (!TextUtils.isEmpty(localSyncID)) {
- // An existing server item has changed
- // If serverSyncVersion is null, there is no edit URL;
- // server won't let this change be written.
- // Just hold onto it, I guess, in case the server permissions
- // change later.
- if (serverSyncVersion != null) {
- boolean recordChanged = (localSyncVersion == null) ||
- !serverSyncVersion.equals(localSyncVersion);
- if (recordChanged) {
- if (localSyncDirty) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "remote record " + serverSyncId
- + " conflicts with local _sync_id " + localSyncID
- + ", local _id " + localRowId);
- }
- conflict = true;
- } else {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG,
- "remote record " +
- serverSyncId +
- " updates local _sync_id " +
- localSyncID + ", local _id " +
- localRowId);
+ if (!TextUtils.isEmpty(localSyncID)) {
+ // An existing server item has changed
+ // If serverSyncVersion is null, there is no edit URL;
+ // server won't let this change be written.
+ // Just hold onto it, I guess, in case the server permissions
+ // change later.
+ if (serverSyncVersion != null) {
+ boolean recordChanged = (localSyncVersion == null) ||
+ !serverSyncVersion.equals(localSyncVersion);
+ if (recordChanged) {
+ if (localSyncDirty) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "remote record " + serverSyncId
+ + " conflicts with local _sync_id " + localSyncID
+ + ", local _id " + localRowId);
+ }
+ conflict = true;
+ } else {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG,
+ "remote record " +
+ serverSyncId +
+ " updates local _sync_id " +
+ localSyncID + ", local _id " +
+ localRowId);
+ }
+ update = true;
}
- update = true;
}
}
+ } else {
+ // the local db doesn't know about this record so add it
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "remote record " + serverSyncId + " is new, inserting");
+ }
+ insert = true;
}
- } else {
- // the local db doesn't know about this record so add it
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "remote record " + serverSyncId + " is new, inserting");
+
+ if (update) {
+ updateRow(localRowId, serverDiffs, diffsCursor);
+ syncResult.stats.numUpdates++;
+ } else if (conflict) {
+ resolveRow(localRowId, serverSyncId, serverDiffs, diffsCursor);
+ syncResult.stats.numUpdates++;
+ } else if (insert) {
+ insertRow(serverDiffs, diffsCursor);
+ syncResult.stats.numInserts++;
}
- insert = true;
}
- if (update) {
- updateRow(localRowId, serverDiffs, diffsCursor);
- syncResult.stats.numUpdates++;
- } else if (conflict) {
- resolveRow(localRowId, serverSyncId, serverDiffs, diffsCursor);
- syncResult.stats.numUpdates++;
- } else if (insert) {
- insertRow(serverDiffs, diffsCursor);
- syncResult.stats.numInserts++;
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "processed " + diffsCount + " server entries");
}
- }
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "processed " + diffsCount + " server entries");
- }
-
- // If tombstones aren't in use delete any remaining local rows that
- // don't have corresponding server rows. Keep the rows that don't
- // have a sync id since those were created locally and haven't been
- // synced to the server yet.
- if (!diffsArePartial) {
- while (!localCursor.isAfterLast() && !TextUtils.isEmpty(localCursor.getString(2))) {
- if (mIsMergeCancelled) {
- localCursor.deactivate();
- deletedCursor.deactivate();
- diffsCursor.deactivate();
- return;
- }
- localCount++;
- final String localSyncId = localCursor.getString(2);
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG,
- "deleting local record " +
- localCursor.getLong(1) +
- " _sync_id " + localSyncId);
- }
- deleteRow(localCursor);
- if (mDeletedTable != null) {
- mDb.delete(mDeletedTable, _SYNC_ID + "=?", new String[] {localSyncId});
+ // If tombstones aren't in use delete any remaining local rows that
+ // don't have corresponding server rows. Keep the rows that don't
+ // have a sync id since those were created locally and haven't been
+ // synced to the server yet.
+ if (!diffsArePartial) {
+ while (!localCursor.isAfterLast() && !TextUtils.isEmpty(localCursor.getString(2))) {
+ if (mIsMergeCancelled) {
+ return;
+ }
+ localCount++;
+ final String localSyncId = localCursor.getString(2);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG,
+ "deleting local record " +
+ localCursor.getLong(1) +
+ " _sync_id " + localSyncId);
+ }
+ deleteRow(localCursor);
+ if (mDeletedTable != null) {
+ mDb.delete(mDeletedTable, _SYNC_ID + "=?", new String[] {localSyncId});
+ }
+ syncResult.stats.numDeletes++;
+ mDb.yieldIfContended();
}
- syncResult.stats.numDeletes++;
- mDb.yieldIfContended();
}
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "checked " + localCount +
+ " local entries");
+ } finally {
+ if (diffsCursor != null) diffsCursor.close();
+ if (localCursor != null) localCursor.close();
+ if (deletedCursor != null) deletedCursor.close();
}
- if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "checked " + localCount +
- " local entries");
- diffsCursor.deactivate();
- localCursor.deactivate();
- deletedCursor.deactivate();
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "applying deletions from the server");
// Apply deletions from the server
if (mDeletedTableURL != null) {
diffsCursor = serverDiffs.query(mDeletedTableURL, null, null, null, null);
-
- while (diffsCursor.moveToNext()) {
- if (mIsMergeCancelled) {
- diffsCursor.deactivate();
- return;
+ try {
+ while (diffsCursor.moveToNext()) {
+ if (mIsMergeCancelled) {
+ return;
+ }
+ // delete all rows that match each element in the diffsCursor
+ fullyDeleteMatchingRows(diffsCursor, account, syncResult);
+ mDb.yieldIfContended();
}
- // delete all rows that match each element in the diffsCursor
- fullyDeleteMatchingRows(diffsCursor, account, syncResult);
- mDb.yieldIfContended();
+ } finally {
+ diffsCursor.close();
}
- diffsCursor.deactivate();
}
}
- private void fullyDeleteMatchingRows(Cursor diffsCursor, String account,
+ private void fullyDeleteMatchingRows(Cursor diffsCursor, Account account,
SyncResult syncResult) {
int serverSyncIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_ID);
final boolean deleteBySyncId = !diffsCursor.isNull(serverSyncIdColumn);
// delete the rows explicitly so that the delete operation can be overridden
- final Cursor c;
final String[] selectionArgs;
- if (deleteBySyncId) {
- selectionArgs = new String[]{diffsCursor.getString(serverSyncIdColumn), account};
- c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_SYNC_ID_AND_ACCOUNT,
- selectionArgs, null, null, null);
- } else {
- int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID);
- selectionArgs = new String[]{diffsCursor.getString(serverSyncLocalIdColumn)};
- c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_ID, selectionArgs,
- null, null, null);
- }
+ Cursor c = null;
try {
+ if (deleteBySyncId) {
+ selectionArgs = new String[]{diffsCursor.getString(serverSyncIdColumn),
+ account.mName, account.mType};
+ c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_SYNC_ID_AND_ACCOUNT,
+ selectionArgs, null, null, null);
+ } else {
+ int serverSyncLocalIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_LOCAL_ID);
+ selectionArgs = new String[]{diffsCursor.getString(serverSyncLocalIdColumn)};
+ c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_ID, selectionArgs,
+ null, null, null);
+ }
c.moveToFirst();
while (!c.isAfterLast()) {
deleteRow(c); // advances the cursor
syncResult.stats.numDeletes++;
}
} finally {
- c.deactivate();
+ if (c != null) c.close();
}
if (deleteBySyncId && mDeletedTable != null) {
mDb.delete(mDeletedTable, SELECT_BY_SYNC_ID_AND_ACCOUNT, selectionArgs);
@@ -516,43 +517,46 @@ public abstract class AbstractTableMerger
* Finds local changes, placing the results in the given result object.
* @param temporaryInstanceFactory As an optimization for the case
* where there are no client-side diffs, mergeResult may initially
- * have no {@link android.content.TempProviderSyncResult#tempContentProvider}. If this is
+ * have no {@link TempProviderSyncResult#tempContentProvider}. If this is
* the first in the sequence of AbstractTableMergers to find
* client-side diffs, it will use the given ContentProvider to
* create a temporary instance and store its {@link
- * ContentProvider} in the mergeResult.
+ * android.content.ContentProvider} in the mergeResult.
* @param account
* @param syncResult
*/
private void findLocalChanges(TempProviderSyncResult mergeResult,
- SyncableContentProvider temporaryInstanceFactory, String account,
+ SyncableContentProvider temporaryInstanceFactory, Account account,
SyncResult syncResult) {
SyncableContentProvider clientDiffs = mergeResult.tempContentProvider;
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "generating client updates");
- final String[] accountSelectionArgs = new String[]{account};
+ final String[] accountSelectionArgs = new String[]{account.mName, account.mType};
// Generate the client updates and insertions
// Create a cursor for dirty records
+ long numInsertsOrUpdates = 0;
Cursor localChangesCursor = mDb.query(mTable, null, SELECT_UNSYNCED, accountSelectionArgs,
null, null, null);
- long numInsertsOrUpdates = localChangesCursor.getCount();
- while (localChangesCursor.moveToNext()) {
- if (mIsMergeCancelled) {
- localChangesCursor.close();
- return;
- }
- if (clientDiffs == null) {
- clientDiffs = temporaryInstanceFactory.getTemporaryInstance();
+ try {
+ numInsertsOrUpdates = localChangesCursor.getCount();
+ while (localChangesCursor.moveToNext()) {
+ if (mIsMergeCancelled) {
+ return;
+ }
+ if (clientDiffs == null) {
+ clientDiffs = temporaryInstanceFactory.getTemporaryInstance();
+ }
+ mValues.clear();
+ cursorRowToContentValues(localChangesCursor, mValues);
+ mValues.remove("_id");
+ DatabaseUtils.cursorLongToContentValues(localChangesCursor, "_id", mValues,
+ _SYNC_LOCAL_ID);
+ clientDiffs.insert(mTableURL, mValues);
}
- mValues.clear();
- cursorRowToContentValues(localChangesCursor, mValues);
- mValues.remove("_id");
- DatabaseUtils.cursorLongToContentValues(localChangesCursor, "_id", mValues,
- _SYNC_LOCAL_ID);
- clientDiffs.insert(mTableURL, mValues);
+ } finally {
+ localChangesCursor.close();
}
- localChangesCursor.close();
// Generate the client deletions
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "generating client deletions");
@@ -561,23 +565,25 @@ public abstract class AbstractTableMerger
if (mDeletedTable != null) {
Cursor deletedCursor = mDb.query(mDeletedTable,
syncIdAndVersionProjection,
- _SYNC_ACCOUNT + "=? AND " + _SYNC_ID + " IS NOT NULL", accountSelectionArgs,
+ _SYNC_ACCOUNT + "=? AND " + _SYNC_ACCOUNT_TYPE + "=? AND "
+ + _SYNC_ID + " IS NOT NULL", accountSelectionArgs,
null, null, mDeletedTable + "." + _SYNC_ID);
-
- numDeletedEntries = deletedCursor.getCount();
- while (deletedCursor.moveToNext()) {
- if (mIsMergeCancelled) {
- deletedCursor.close();
- return;
- }
- if (clientDiffs == null) {
- clientDiffs = temporaryInstanceFactory.getTemporaryInstance();
+ try {
+ numDeletedEntries = deletedCursor.getCount();
+ while (deletedCursor.moveToNext()) {
+ if (mIsMergeCancelled) {
+ return;
+ }
+ if (clientDiffs == null) {
+ clientDiffs = temporaryInstanceFactory.getTemporaryInstance();
+ }
+ mValues.clear();
+ DatabaseUtils.cursorRowToContentValues(deletedCursor, mValues);
+ clientDiffs.insert(mDeletedTableURL, mValues);
}
- mValues.clear();
- DatabaseUtils.cursorRowToContentValues(deletedCursor, mValues);
- clientDiffs.insert(mDeletedTableURL, mValues);
+ } finally {
+ deletedCursor.close();
}
- deletedCursor.close();
}
if (clientDiffs != null) {
diff --git a/core/java/android/content/ActiveSyncInfo.java b/core/java/android/content/ActiveSyncInfo.java
index 63be8d1..209dffa 100644
--- a/core/java/android/content/ActiveSyncInfo.java
+++ b/core/java/android/content/ActiveSyncInfo.java
@@ -16,17 +16,18 @@
package android.content;
+import android.accounts.Account;
import android.os.Parcel;
import android.os.Parcelable.Creator;
/** @hide */
public class ActiveSyncInfo {
public final int authorityId;
- public final String account;
+ public final Account account;
public final String authority;
public final long startTime;
- ActiveSyncInfo(int authorityId, String account, String authority,
+ ActiveSyncInfo(int authorityId, Account account, String authority,
long startTime) {
this.authorityId = authorityId;
this.account = account;
@@ -40,14 +41,14 @@ public class ActiveSyncInfo {
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(authorityId);
- parcel.writeString(account);
+ account.writeToParcel(parcel, 0);
parcel.writeString(authority);
parcel.writeLong(startTime);
}
ActiveSyncInfo(Parcel parcel) {
authorityId = parcel.readInt();
- account = parcel.readString();
+ account = new Account(parcel);
authority = parcel.readString();
startTime = parcel.readLong();
}
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 5cc5730..4e631c4 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -32,6 +32,7 @@ import android.os.ParcelFileDescriptor;
import java.io.File;
import java.io.FileNotFoundException;
+import java.util.ArrayList;
/**
* Content providers are one of the primary building blocks of Android applications, providing
@@ -130,6 +131,12 @@ public abstract class ContentProvider implements ComponentCallbacks {
selectionArgs, sortOrder);
}
+ public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
+ String sortOrder) {
+ checkReadPermission(uri);
+ return ContentProvider.this.queryEntities(uri, selection, selectionArgs, sortOrder);
+ }
+
public String getType(Uri uri) {
return ContentProvider.this.getType(uri);
}
@@ -145,6 +152,25 @@ public abstract class ContentProvider implements ComponentCallbacks {
return ContentProvider.this.bulkInsert(uri, initialValues);
}
+ public Uri insertEntity(Uri uri, Entity entities) {
+ checkWritePermission(uri);
+ return ContentProvider.this.insertEntity(uri, entities);
+ }
+
+ public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
+ throws OperationApplicationException {
+ for (ContentProviderOperation operation : operations) {
+ if (operation.isReadOperation()) {
+ checkReadPermission(operation.getUri());
+ }
+
+ if (operation.isWriteOperation()) {
+ checkWritePermission(operation.getUri());
+ }
+ }
+ return ContentProvider.this.applyBatch(operations);
+ }
+
public int delete(Uri uri, String selection, String[] selectionArgs) {
checkWritePermission(uri);
return ContentProvider.this.delete(uri, selection, selectionArgs);
@@ -156,6 +182,11 @@ public abstract class ContentProvider implements ComponentCallbacks {
return ContentProvider.this.update(uri, values, selection, selectionArgs);
}
+ public int updateEntity(Uri uri, Entity entity) {
+ checkWritePermission(uri);
+ return ContentProvider.this.updateEntity(uri, entity);
+ }
+
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
if (mode != null && mode.startsWith("rw")) checkWritePermission(uri);
@@ -170,12 +201,6 @@ public abstract class ContentProvider implements ComponentCallbacks {
return ContentProvider.this.openAssetFile(uri, mode);
}
- public ISyncAdapter getSyncAdapter() {
- checkWritePermission(null);
- SyncAdapter sa = ContentProvider.this.getSyncAdapter();
- return sa != null ? sa.getISyncAdapter() : null;
- }
-
private void checkReadPermission(Uri uri) {
final String rperm = getReadPermission();
final int pid = Binder.getCallingPid();
@@ -334,6 +359,11 @@ public abstract class ContentProvider implements ComponentCallbacks {
public abstract Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder);
+ public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
+ String sortOrder) {
+ throw new UnsupportedOperationException();
+ }
+
/**
* Return the MIME type of the data at the given URI. This should start with
* <code>vnd.android.cursor.item</code> for a single record,
@@ -384,6 +414,10 @@ public abstract class ContentProvider implements ComponentCallbacks {
return numValues;
}
+ public Uri insertEntity(Uri uri, Entity entity) {
+ throw new UnsupportedOperationException();
+ }
+
/**
* A request to delete one or more rows. The selection clause is applied when performing
* the deletion, allowing the operation to affect multiple rows in a
@@ -428,6 +462,10 @@ public abstract class ContentProvider implements ComponentCallbacks {
public abstract int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs);
+ public int updateEntity(Uri uri, Entity entity) {
+ throw new UnsupportedOperationException();
+ }
+
/**
* Open a file blob associated with a content URI.
* This method can be called from multiple
@@ -551,23 +589,6 @@ public abstract class ContentProvider implements ComponentCallbacks {
}
/**
- * Get the sync adapter that is to be used by this content provider.
- * This is intended for use by the sync system. If null then this
- * content provider is considered not syncable.
- * This method can be called from multiple
- * threads, as described in
- * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
- * Processes and Threads</a>.
- *
- * @return the SyncAdapter that is to be used by this ContentProvider, or null
- * if this ContentProvider is not syncable
- * @hide
- */
- public SyncAdapter getSyncAdapter() {
- return null;
- }
-
- /**
* Returns true if this instance is a temporary content provider.
* @return true if this instance is a temporary content provider
*/
@@ -607,4 +628,27 @@ public abstract class ContentProvider implements ComponentCallbacks {
ContentProvider.this.onCreate();
}
}
-}
+
+ /**
+ * Applies each of the {@link ContentProviderOperation} objects and returns an array
+ * of their results. Passes through OperationApplicationException, which may be thrown
+ * by the call to {@link ContentProviderOperation#apply}.
+ * If all the applications succeed then a {@link ContentProviderResult} array with the
+ * same number of elements as the operations will be returned. It is implementation-specific
+ * how many, if any, operations will have been successfully applied if a call to
+ * apply results in a {@link OperationApplicationException}.
+ * @param operations the operations to apply
+ * @return the results of the applications
+ * @throws OperationApplicationException thrown if an application fails.
+ * See {@link ContentProviderOperation#apply} for more information.
+ */
+ public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
+ throws OperationApplicationException {
+ final int numOperations = operations.size();
+ final ContentProviderResult[] results = new ContentProviderResult[numOperations];
+ for (int i = 0; i < numOperations; i++) {
+ results[i] = operations.get(i).apply(this, results, i);
+ }
+ return results;
+ }
+} \ No newline at end of file
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
new file mode 100644
index 0000000..452653e
--- /dev/null
+++ b/core/java/android/content/ContentProviderClient.java
@@ -0,0 +1,135 @@
+/*
+ * 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.content;
+
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.os.ParcelFileDescriptor;
+import android.content.res.AssetFileDescriptor;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+
+/**
+ * The public interface object used to interact with a {@link ContentProvider}. This is obtained by
+ * calling {@link ContentResolver#acquireContentProviderClient}. This object must be released
+ * using {@link #release} in order to indicate to the system that the {@link ContentProvider} is
+ * no longer needed and can be killed to free up resources.
+ */
+public class ContentProviderClient {
+ private final IContentProvider mContentProvider;
+ private final ContentResolver mContentResolver;
+
+ /**
+ * @hide
+ */
+ ContentProviderClient(ContentResolver contentResolver, IContentProvider contentProvider) {
+ mContentProvider = contentProvider;
+ mContentResolver = contentResolver;
+ }
+
+ /** see {@link ContentProvider#query} */
+ public Cursor query(Uri url, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) throws RemoteException {
+ return mContentProvider.query(url, projection, selection, selectionArgs, sortOrder);
+ }
+
+ /** see {@link ContentProvider#getType} */
+ public String getType(Uri url) throws RemoteException {
+ return mContentProvider.getType(url);
+ }
+
+ /** see {@link ContentProvider#insert} */
+ public Uri insert(Uri url, ContentValues initialValues)
+ throws RemoteException {
+ return mContentProvider.insert(url, initialValues);
+ }
+
+ /** see {@link ContentProvider#bulkInsert} */
+ public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException {
+ return mContentProvider.bulkInsert(url, initialValues);
+ }
+
+ /** see {@link ContentProvider#delete} */
+ public int delete(Uri url, String selection, String[] selectionArgs)
+ throws RemoteException {
+ return mContentProvider.delete(url, selection, selectionArgs);
+ }
+
+ /** see {@link ContentProvider#update} */
+ public int update(Uri url, ContentValues values, String selection,
+ String[] selectionArgs) throws RemoteException {
+ return mContentProvider.update(url, values, selection, selectionArgs);
+ }
+
+ /** see {@link ContentProvider#openFile} */
+ public ParcelFileDescriptor openFile(Uri url, String mode)
+ throws RemoteException, FileNotFoundException {
+ return mContentProvider.openFile(url, mode);
+ }
+
+ /** see {@link ContentProvider#openAssetFile} */
+ public AssetFileDescriptor openAssetFile(Uri url, String mode)
+ throws RemoteException, FileNotFoundException {
+ return mContentProvider.openAssetFile(url, mode);
+ }
+
+ /** see {@link ContentProvider#queryEntities} */
+ public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
+ String sortOrder) throws RemoteException {
+ return mContentProvider.queryEntities(uri, selection, selectionArgs, sortOrder);
+ }
+
+ /** see {@link ContentProvider#insertEntity} */
+ public Uri insertEntity(Uri uri, Entity entity) throws RemoteException {
+ return mContentProvider.insertEntity(uri, entity);
+ }
+
+ /** see {@link ContentProvider#updateEntity} */
+ public int updateEntity(Uri uri, Entity entity) throws RemoteException {
+ return mContentProvider.updateEntity(uri, entity);
+ }
+
+ /** see {@link ContentProvider#applyBatch} */
+ public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
+ throws RemoteException, OperationApplicationException {
+ return mContentProvider.applyBatch(operations);
+ }
+
+ /**
+ * Call this to indicate to the system that the associated {@link ContentProvider} is no
+ * longer needed by this {@link ContentProviderClient}.
+ * @return true if this was release, false if it was already released
+ */
+ public boolean release() {
+ return mContentResolver.releaseProvider(mContentProvider);
+ }
+
+ /**
+ * Get a reference to the {@link ContentProvider} that is associated with this
+ * client. If the {@link ContentProvider} is running in a different process then
+ * null will be returned. This can be used if you know you are running in the same
+ * process as a provider, and want to get direct access to its implementation details.
+ *
+ * @return If the associated {@link ContentProvider} is local, returns it.
+ * Otherwise returns null.
+ */
+ public ContentProvider getLocalContentProvider() {
+ return ContentProvider.coerceToLocalContentProvider(mContentProvider);
+ }
+}
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index e5e3f74..a4c217b 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -33,6 +33,7 @@ import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import java.io.FileNotFoundException;
+import java.util.ArrayList;
/**
* {@hide}
@@ -105,6 +106,20 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
return true;
}
+ case QUERY_ENTITIES_TRANSACTION:
+ {
+ data.enforceInterface(IContentProvider.descriptor);
+ Uri url = Uri.CREATOR.createFromParcel(data);
+ String selection = data.readString();
+ String[] selectionArgs = data.readStringArray();
+ String sortOrder = data.readString();
+ EntityIterator entityIterator = queryEntities(url, selection, selectionArgs,
+ sortOrder);
+ reply.writeNoException();
+ reply.writeStrongBinder(new IEntityIteratorImpl(entityIterator).asBinder());
+ return true;
+ }
+
case GET_TYPE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
@@ -140,6 +155,43 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
return true;
}
+ case INSERT_ENTITIES_TRANSACTION:
+ {
+ data.enforceInterface(IContentProvider.descriptor);
+ Uri uri = Uri.CREATOR.createFromParcel(data);
+ Entity entity = (Entity) data.readParcelable(null);
+ Uri newUri = insertEntity(uri, entity);
+ reply.writeNoException();
+ Uri.writeToParcel(reply, newUri);
+ return true;
+ }
+
+ case UPDATE_ENTITIES_TRANSACTION:
+ {
+ data.enforceInterface(IContentProvider.descriptor);
+ Uri uri = Uri.CREATOR.createFromParcel(data);
+ Entity entity = (Entity) data.readParcelable(null);
+ int count = updateEntity(uri, entity);
+ reply.writeNoException();
+ reply.writeInt(count);
+ return true;
+ }
+
+ case APPLY_BATCH_TRANSACTION:
+ {
+ data.enforceInterface(IContentProvider.descriptor);
+ final int numOperations = data.readInt();
+ final ArrayList<ContentProviderOperation> operations =
+ new ArrayList<ContentProviderOperation>(numOperations);
+ for (int i = 0; i < numOperations; i++) {
+ operations.add(i, ContentProviderOperation.CREATOR.createFromParcel(data));
+ }
+ final ContentProviderResult[] results = applyBatch(operations);
+ reply.writeNoException();
+ reply.writeTypedArray(results, 0);
+ return true;
+ }
+
case DELETE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
@@ -206,15 +258,6 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
}
return true;
}
-
- case GET_SYNC_ADAPTER_TRANSACTION:
- {
- data.enforceInterface(IContentProvider.descriptor);
- ISyncAdapter sa = getSyncAdapter();
- reply.writeNoException();
- reply.writeStrongBinder(sa != null ? sa.asBinder() : null);
- return true;
- }
}
} catch (Exception e) {
DatabaseUtils.writeExceptionToParcel(reply, e);
@@ -224,6 +267,25 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
return super.onTransact(code, data, reply, flags);
}
+ private class IEntityIteratorImpl extends IEntityIterator.Stub {
+ private final EntityIterator mEntityIterator;
+
+ IEntityIteratorImpl(EntityIterator iterator) {
+ mEntityIterator = iterator;
+ }
+ public boolean hasNext() throws RemoteException {
+ return mEntityIterator.hasNext();
+ }
+
+ public Entity next() throws RemoteException {
+ return mEntityIterator.next();
+ }
+
+ public void close() throws RemoteException {
+ mEntityIterator.close();
+ }
+ }
+
public IBinder asBinder()
{
return this;
@@ -297,7 +359,7 @@ final class ContentProviderProxy implements IContentProvider
BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
IBulkCursor bulkCursor = bulkQuery(url, projection, selection, selectionArgs, sortOrder,
adaptor.getObserver(), window);
-
+
if (bulkCursor == null) {
return null;
}
@@ -305,6 +367,54 @@ final class ContentProviderProxy implements IContentProvider
return adaptor;
}
+ public EntityIterator queryEntities(Uri url, String selection, String[] selectionArgs,
+ String sortOrder)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+
+ data.writeInterfaceToken(IContentProvider.descriptor);
+
+ url.writeToParcel(data, 0);
+ data.writeString(selection);
+ data.writeStringArray(selectionArgs);
+ data.writeString(sortOrder);
+
+ mRemote.transact(IContentProvider.QUERY_ENTITIES_TRANSACTION, data, reply, 0);
+
+ DatabaseUtils.readExceptionFromParcel(reply);
+
+ IBinder entityIteratorBinder = reply.readStrongBinder();
+
+ data.recycle();
+ reply.recycle();
+
+ return new RemoteEntityIterator(IEntityIterator.Stub.asInterface(entityIteratorBinder));
+ }
+
+ static class RemoteEntityIterator implements EntityIterator {
+ private final IEntityIterator mEntityIterator;
+ RemoteEntityIterator(IEntityIterator entityIterator) {
+ mEntityIterator = entityIterator;
+ }
+
+ public boolean hasNext() throws RemoteException {
+ return mEntityIterator.hasNext();
+ }
+
+ public Entity next() throws RemoteException {
+ return mEntityIterator.next();
+ }
+
+ public void close() {
+ try {
+ mEntityIterator.close();
+ } catch (RemoteException e) {
+ // doesn't matter
+ }
+ }
+ }
+
public String getType(Uri url) throws RemoteException
{
Parcel data = Parcel.obtain();
@@ -366,6 +476,66 @@ final class ContentProviderProxy implements IContentProvider
return count;
}
+ public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
+ throws RemoteException, OperationApplicationException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+
+ data.writeInterfaceToken(IContentProvider.descriptor);
+ data.writeInt(operations.size());
+ for (ContentProviderOperation operation : operations) {
+ operation.writeToParcel(data, 0);
+ }
+ mRemote.transact(IContentProvider.APPLY_BATCH_TRANSACTION, data, reply, 0);
+
+ DatabaseUtils.readExceptionWithOperationApplicationExceptionFromParcel(reply);
+ final ContentProviderResult[] results =
+ reply.createTypedArray(ContentProviderResult.CREATOR);
+
+ data.recycle();
+ reply.recycle();
+
+ return results;
+ }
+
+ public Uri insertEntity(Uri uri, Entity entity) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+
+ try {
+ data.writeInterfaceToken(IContentProvider.descriptor);
+ uri.writeToParcel(data, 0);
+ data.writeParcelable(entity, 0);
+
+ mRemote.transact(IContentProvider.INSERT_ENTITIES_TRANSACTION, data, reply, 0);
+
+ DatabaseUtils.readExceptionFromParcel(reply);
+ return Uri.CREATOR.createFromParcel(reply);
+ } finally {
+ data.recycle();
+ reply.recycle();
+ }
+ }
+
+ public int updateEntity(Uri uri, Entity entity) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+
+ try {
+ data.writeInterfaceToken(IContentProvider.descriptor);
+ uri.writeToParcel(data, 0);
+ data.writeParcelable(entity, 0);
+
+ mRemote.transact(IContentProvider.UPDATE_ENTITIES_TRANSACTION, data, reply, 0);
+
+ DatabaseUtils.readExceptionFromParcel(reply);
+ return reply.readInt();
+ } finally {
+ data.recycle();
+ reply.recycle();
+ }
+ }
+
public int delete(Uri url, String selection, String[] selectionArgs)
throws RemoteException {
Parcel data = Parcel.obtain();
@@ -456,23 +626,6 @@ final class ContentProviderProxy implements IContentProvider
return fd;
}
- public ISyncAdapter getSyncAdapter() throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
-
- data.writeInterfaceToken(IContentProvider.descriptor);
-
- mRemote.transact(IContentProvider.GET_SYNC_ADAPTER_TRANSACTION, data, reply, 0);
-
- DatabaseUtils.readExceptionFromParcel(reply);
- ISyncAdapter syncAdapter = ISyncAdapter.Stub.asInterface(reply.readStrongBinder());
-
- data.recycle();
- reply.recycle();
-
- return syncAdapter;
- }
-
private IBinder mRemote;
}
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
new file mode 100644
index 0000000..001af16
--- /dev/null
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -0,0 +1,523 @@
+/*
+ * 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.content;
+
+import android.net.Uri;
+import android.database.Cursor;
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.os.Debug;
+
+import java.util.Map;
+import java.util.HashMap;
+
+public class ContentProviderOperation implements Parcelable {
+ private final static int TYPE_INSERT = 1;
+ private final static int TYPE_UPDATE = 2;
+ private final static int TYPE_DELETE = 3;
+ private final static int TYPE_COUNT = 4;
+
+ private final int mType;
+ private final Uri mUri;
+ private final String mSelection;
+ private final String[] mSelectionArgs;
+ private final ContentValues mValues;
+ private final Integer mExpectedCount;
+ private final ContentValues mValuesBackReferences;
+ private final Map<Integer, Integer> mSelectionArgsBackReferences;
+
+ private static final String[] COUNT_COLUMNS = new String[]{"count(*)"};
+
+ /**
+ * Creates a {@link ContentProviderOperation} by copying the contents of a
+ * {@link Builder}.
+ */
+ private ContentProviderOperation(Builder builder) {
+ mType = builder.mType;
+ mUri = builder.mUri;
+ mValues = builder.mValues;
+ mSelection = builder.mSelection;
+ mSelectionArgs = builder.mSelectionArgs;
+ mExpectedCount = builder.mExpectedCount;
+ mSelectionArgsBackReferences = builder.mSelectionArgsBackReferences;
+ mValuesBackReferences = builder.mValuesBackReferences;
+ }
+
+ private ContentProviderOperation(Parcel source) {
+ mType = source.readInt();
+ mUri = Uri.CREATOR.createFromParcel(source);
+ mValues = source.readInt() != 0 ? ContentValues.CREATOR.createFromParcel(source) : null;
+ mSelection = source.readInt() != 0 ? source.readString() : null;
+ mSelectionArgs = source.readInt() != 0 ? source.readStringArray() : null;
+ mExpectedCount = source.readInt() != 0 ? source.readInt() : null;
+ mValuesBackReferences = source.readInt() != 0
+
+ ? ContentValues.CREATOR.createFromParcel(source)
+ : null;
+ mSelectionArgsBackReferences = source.readInt() != 0
+ ? new HashMap<Integer, Integer>()
+ : null;
+ if (mSelectionArgsBackReferences != null) {
+ final int count = source.readInt();
+ for (int i = 0; i < count; i++) {
+ mSelectionArgsBackReferences.put(source.readInt(), source.readInt());
+ }
+ }
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mType);
+ Uri.writeToParcel(dest, mUri);
+ if (mValues != null) {
+ dest.writeInt(1);
+ mValues.writeToParcel(dest, 0);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mSelection != null) {
+ dest.writeInt(1);
+ dest.writeString(mSelection);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mSelectionArgs != null) {
+ dest.writeInt(1);
+ dest.writeStringArray(mSelectionArgs);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mExpectedCount != null) {
+ dest.writeInt(1);
+ dest.writeInt(mExpectedCount);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mValuesBackReferences != null) {
+ dest.writeInt(1);
+ mValuesBackReferences.writeToParcel(dest, 0);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mSelectionArgsBackReferences != null) {
+ dest.writeInt(1);
+ dest.writeInt(mSelectionArgsBackReferences.size());
+ for (Map.Entry<Integer, Integer> entry : mSelectionArgsBackReferences.entrySet()) {
+ dest.writeInt(entry.getKey());
+ dest.writeInt(entry.getValue());
+ }
+ } else {
+ dest.writeInt(0);
+ }
+ }
+
+ /**
+ * Create a {@link Builder} suitable for building an insert {@link ContentProviderOperation}.
+ * @param uri The {@link Uri} that is the target of the insert.
+ * @return a {@link Builder}
+ */
+ public static Builder newInsert(Uri uri) {
+ return new Builder(TYPE_INSERT, uri);
+ }
+
+ /**
+ * Create a {@link Builder} suitable for building an update {@link ContentProviderOperation}.
+ * @param uri The {@link Uri} that is the target of the update.
+ * @return a {@link Builder}
+ */
+ public static Builder newUpdate(Uri uri) {
+ return new Builder(TYPE_UPDATE, uri);
+ }
+
+ /**
+ * Create a {@link Builder} suitable for building a delete {@link ContentProviderOperation}.
+ * @param uri The {@link Uri} that is the target of the delete.
+ * @return a {@link Builder}
+ */
+ public static Builder newDelete(Uri uri) {
+ return new Builder(TYPE_DELETE, uri);
+ }
+
+ /**
+ * Create a {@link Builder} suitable for building a count query. When used in conjunction
+ * with {@link Builder#withExpectedCount(int)} this is useful for checking that the
+ * uri/selection has the expected number of rows.
+ * {@link ContentProviderOperation}.
+ * @param uri The {@link Uri} to query.
+ * @return a {@link Builder}
+ */
+ public static Builder newCountQuery(Uri uri) {
+ return new Builder(TYPE_COUNT, uri);
+ }
+
+ public Uri getUri() {
+ return mUri;
+ }
+
+ public boolean isWriteOperation() {
+ return mType == TYPE_DELETE || mType == TYPE_INSERT || mType == TYPE_UPDATE;
+ }
+
+ public boolean isReadOperation() {
+ return mType == TYPE_COUNT;
+ }
+
+ /**
+ * Applies this operation using the given provider. The backRefs array is used to resolve any
+ * back references that were requested using
+ * {@link Builder#withValueBackReferences(ContentValues)} and
+ * {@link Builder#withSelectionBackReference}.
+ * @param provider the {@link ContentProvider} on which this batch is applied
+ * @param backRefs a {@link ContentProviderResult} array that will be consulted
+ * to resolve any requested back references.
+ * @param numBackRefs the number of valid results on the backRefs array.
+ * @return a {@link ContentProviderResult} that contains either the {@link Uri} of the inserted
+ * row if this was an insert otherwise the number of rows affected.
+ * @throws OperationApplicationException thrown if either the insert fails or
+ * if the number of rows affected didn't match the expected count
+ */
+ public ContentProviderResult apply(ContentProvider provider, ContentProviderResult[] backRefs,
+ int numBackRefs) throws OperationApplicationException {
+ ContentValues values = resolveValueBackReferences(backRefs, numBackRefs);
+ String[] selectionArgs =
+ resolveSelectionArgsBackReferences(backRefs, numBackRefs);
+
+ if (mType == TYPE_INSERT) {
+ Uri newUri = provider.insert(mUri, values);
+ if (newUri == null) {
+ throw new OperationApplicationException("insert failed");
+ }
+ return new ContentProviderResult(newUri);
+ }
+
+ int numRows;
+ if (mType == TYPE_DELETE) {
+ numRows = provider.delete(mUri, mSelection, selectionArgs);
+ } else if (mType == TYPE_UPDATE) {
+ numRows = provider.update(mUri, values, mSelection, selectionArgs);
+ } else if (mType == TYPE_COUNT) {
+ Cursor cursor = provider.query(mUri, COUNT_COLUMNS, mSelection, selectionArgs, null);
+ try {
+ if (!cursor.moveToNext()) {
+ throw new RuntimeException("since we are doing a count query we should always "
+ + "be able to move to the first row");
+ }
+ if (cursor.getCount() != 1) {
+ throw new RuntimeException("since we are doing a count query there should "
+ + "always be exacly row, found " + cursor.getCount());
+ }
+ numRows = cursor.getInt(0);
+ } finally {
+ cursor.close();
+ }
+ } else {
+ throw new IllegalStateException("bad type, " + mType);
+ }
+
+ if (mExpectedCount != null && mExpectedCount != numRows) {
+ throw new OperationApplicationException("wrong number of rows: " + numRows);
+ }
+
+ return new ContentProviderResult(numRows);
+ }
+
+ /**
+ * The ContentValues back references are represented as a ContentValues object where the
+ * key refers to a column and the value is an index of the back reference whose
+ * valued should be associated with the column.
+ * @param backRefs an array of previous results
+ * @param numBackRefs the number of valid previous results in backRefs
+ * @return the ContentValues that should be used in this operation application after
+ * expansion of back references. This can be called if either mValues or mValuesBackReferences
+ * is null
+ * @VisibleForTesting this is intended to be a private method but it is exposed for
+ * unit testing purposes
+ */
+ public ContentValues resolveValueBackReferences(
+ ContentProviderResult[] backRefs, int numBackRefs) {
+ if (mValuesBackReferences == null) {
+ return mValues;
+ }
+ final ContentValues values;
+ if (mValues == null) {
+ values = new ContentValues();
+ } else {
+ values = new ContentValues(mValues);
+ }
+ for (Map.Entry<String, Object> entry : mValuesBackReferences.valueSet()) {
+ String key = entry.getKey();
+ Integer backRefIndex = mValuesBackReferences.getAsInteger(key);
+ if (backRefIndex == null) {
+ throw new IllegalArgumentException("values backref " + key + " is not an integer");
+ }
+ values.put(key, backRefToValue(backRefs, numBackRefs, backRefIndex));
+ }
+ return values;
+ }
+
+ /**
+ * The Selection Arguments back references are represented as a Map of Integer->Integer where
+ * the key is an index into the selection argument array (see {@link Builder#withSelection})
+ * and the value is the index of the previous result that should be used for that selection
+ * argument array slot.
+ * @param backRefs an array of previous results
+ * @param numBackRefs the number of valid previous results in backRefs
+ * @return the ContentValues that should be used in this operation application after
+ * expansion of back references. This can be called if either mValues or mValuesBackReferences
+ * is null
+ * @VisibleForTesting this is intended to be a private method but it is exposed for
+ * unit testing purposes
+ */
+ public String[] resolveSelectionArgsBackReferences(
+ ContentProviderResult[] backRefs, int numBackRefs) {
+ if (mSelectionArgsBackReferences == null) {
+ return mSelectionArgs;
+ }
+ String[] newArgs = new String[mSelectionArgs.length];
+ System.arraycopy(mSelectionArgs, 0, newArgs, 0, mSelectionArgs.length);
+ for (Map.Entry<Integer, Integer> selectionArgBackRef
+ : mSelectionArgsBackReferences.entrySet()) {
+ final Integer selectionArgIndex = selectionArgBackRef.getKey();
+ final int backRefIndex = selectionArgBackRef.getValue();
+ newArgs[selectionArgIndex] = backRefToValue(backRefs, numBackRefs, backRefIndex);
+ }
+ return newArgs;
+ }
+
+ /**
+ * Return the string representation of the requested back reference.
+ * @param backRefs an array of results
+ * @param numBackRefs the number of items in the backRefs array that are valid
+ * @param backRefIndex which backRef to be used
+ * @throws ArrayIndexOutOfBoundsException thrown if the backRefIndex is larger than
+ * the numBackRefs
+ * @return the string representation of the requested back reference.
+ */
+ private static String backRefToValue(ContentProviderResult[] backRefs, int numBackRefs,
+ Integer backRefIndex) {
+ if (backRefIndex >= numBackRefs) {
+ throw new ArrayIndexOutOfBoundsException("asked for back ref " + backRefIndex
+ + " but there are only " + numBackRefs + " back refs");
+ }
+ ContentProviderResult backRef = backRefs[backRefIndex];
+ String backRefValue;
+ if (backRef.uri != null) {
+ backRefValue = backRef.uri.getLastPathSegment();
+ } else {
+ backRefValue = String.valueOf(backRef.count);
+ }
+ return backRefValue;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<ContentProviderOperation> CREATOR =
+ new Creator<ContentProviderOperation>() {
+ public ContentProviderOperation createFromParcel(Parcel source) {
+ return new ContentProviderOperation(source);
+ }
+
+ public ContentProviderOperation[] newArray(int size) {
+ return new ContentProviderOperation[size];
+ }
+ };
+
+
+ /**
+ * Used to add parameters to a {@link ContentProviderOperation}. The {@link Builder} is
+ * first created by calling {@link ContentProviderOperation#newInsert(android.net.Uri)},
+ * {@link ContentProviderOperation#newUpdate(android.net.Uri)},
+ * {@link ContentProviderOperation#newDelete(android.net.Uri)} or
+ * {@link ContentProviderOperation#newCountQuery(android.net.Uri)}. The withXXX methods
+ * can then be used to add parameters to the builder. See the specific methods to find for
+ * which {@link Builder} type each is allowed. Call {@link #build} to create the
+ * {@link ContentProviderOperation} once all the parameters have been supplied.
+ */
+ public static class Builder {
+ private final int mType;
+ private final Uri mUri;
+ private String mSelection;
+ private String[] mSelectionArgs;
+ private ContentValues mValues;
+ private Integer mExpectedCount;
+ private ContentValues mValuesBackReferences;
+ private Map<Integer, Integer> mSelectionArgsBackReferences;
+
+ /** Create a {@link Builder} of a given type. The uri must not be null. */
+ private Builder(int type, Uri uri) {
+ if (uri == null) {
+ throw new IllegalArgumentException("uri must not be null");
+ }
+ mType = type;
+ mUri = uri;
+ }
+
+ /** Create a ContentProviderOperation from this {@link Builder}. */
+ public ContentProviderOperation build() {
+ return new ContentProviderOperation(this);
+ }
+
+ /**
+ * Add a {@link ContentValues} of back references. The key is the name of the column
+ * and the value is an integer that is the index of the previous result whose
+ * value should be used for the column. The value is added as a {@link String}.
+ * A column value from the back references takes precedence over a value specified in
+ * {@link #withValues}.
+ * This can only be used with builders of type insert or update.
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withValueBackReferences(ContentValues backReferences) {
+ if (mType != TYPE_INSERT && mType != TYPE_UPDATE) {
+ throw new IllegalArgumentException(
+ "only inserts and updates can have value back-references");
+ }
+ mValuesBackReferences = backReferences;
+ return this;
+ }
+
+ /**
+ * Add a ContentValues back reference.
+ * A column value from the back references takes precedence over a value specified in
+ * {@link #withValues}.
+ * This can only be used with builders of type insert or update.
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withValueBackReference(String key, int previousResult) {
+ if (mType != TYPE_INSERT && mType != TYPE_UPDATE) {
+ throw new IllegalArgumentException(
+ "only inserts and updates can have value back-references");
+ }
+ if (mValuesBackReferences == null) {
+ mValuesBackReferences = new ContentValues();
+ }
+ mValuesBackReferences.put(key, previousResult);
+ return this;
+ }
+
+ /**
+ * Add a back references as a selection arg. Any value at that index of the selection arg
+ * that was specified by {@link #withSelection} will be overwritten.
+ * This can only be used with builders of type update, delete, or count query.
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withSelectionBackReference(int selectionArgIndex, int previousResult) {
+ if (mType != TYPE_COUNT && mType != TYPE_UPDATE && mType != TYPE_DELETE) {
+ throw new IllegalArgumentException(
+ "only deletes, updates and counts can have selection back-references");
+ }
+ if (mSelectionArgsBackReferences == null) {
+ mSelectionArgsBackReferences = new HashMap<Integer, Integer>();
+ }
+ mSelectionArgsBackReferences.put(selectionArgIndex, previousResult);
+ return this;
+ }
+
+ /**
+ * The ContentValues to use. This may be null. These values may be overwritten by
+ * the corresponding value specified by {@link #withValueBackReference} or by
+ * future calls to {@link #withValues} or {@link #withValue}.
+ * This can only be used with builders of type insert or update.
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withValues(ContentValues values) {
+ if (mType != TYPE_INSERT && mType != TYPE_UPDATE) {
+ throw new IllegalArgumentException("only inserts and updates can have values");
+ }
+ if (mValues == null) {
+ mValues = new ContentValues();
+ }
+ mValues.putAll(values);
+ return this;
+ }
+
+ /**
+ * A value to insert or update. This value may be overwritten by
+ * the corresponding value specified by {@link #withValueBackReference}.
+ * This can only be used with builders of type insert or update.
+ * @param key the name of this value
+ * @param value the value itself. the type must be acceptable for insertion by
+ * {@link ContentValues#put}
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withValue(String key, Object value) {
+ if (mType != TYPE_INSERT && mType != TYPE_UPDATE) {
+ throw new IllegalArgumentException("only inserts and updates can have values");
+ }
+ if (mValues == null) {
+ mValues = new ContentValues();
+ }
+ if (value == null) {
+ mValues.putNull(key);
+ } else if (value instanceof String) {
+ mValues.put(key, (String) value);
+ } else if (value instanceof Byte) {
+ mValues.put(key, (Byte) value);
+ } else if (value instanceof Short) {
+ mValues.put(key, (Short) value);
+ } else if (value instanceof Integer) {
+ mValues.put(key, (Integer) value);
+ } else if (value instanceof Long) {
+ mValues.put(key, (Long) value);
+ } else if (value instanceof Float) {
+ mValues.put(key, (Float) value);
+ } else if (value instanceof Double) {
+ mValues.put(key, (Double) value);
+ } else if (value instanceof Boolean) {
+ mValues.put(key, (Boolean) value);
+ } else if (value instanceof byte[]) {
+ mValues.put(key, (byte[]) value);
+ } else {
+ throw new IllegalArgumentException("bad value type: " + value.getClass().getName());
+ }
+ return this;
+ }
+
+ /**
+ * The selection and arguments to use. An occurrence of '?' in the selection will be
+ * replaced with the corresponding occurence of the selection argument. Any of the
+ * selection arguments may be overwritten by a selection argument back reference as
+ * specified by {@link #withSelectionBackReference}.
+ * This can only be used with builders of type update, delete, or count query.
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withSelection(String selection, String[] selectionArgs) {
+ if (mType != TYPE_DELETE && mType != TYPE_UPDATE && mType != TYPE_COUNT) {
+ throw new IllegalArgumentException(
+ "only deletes, updates and counts can have selections");
+ }
+ mSelection = selection;
+ mSelectionArgs = selectionArgs;
+ return this;
+ }
+
+ /**
+ * If set then if the number of rows affected by this operation do not match
+ * this count {@link OperationApplicationException} will be throw.
+ * This can only be used with builders of type update, delete, or count query.
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withExpectedCount(int count) {
+ if (mType != TYPE_DELETE && mType != TYPE_UPDATE && mType != TYPE_COUNT) {
+ throw new IllegalArgumentException(
+ "only deletes, updates and counts can have expected counts");
+ }
+ mExpectedCount = count;
+ return this;
+ }
+ }
+}
diff --git a/core/java/android/content/ContentProviderResult.java b/core/java/android/content/ContentProviderResult.java
new file mode 100644
index 0000000..5d188ef
--- /dev/null
+++ b/core/java/android/content/ContentProviderResult.java
@@ -0,0 +1,84 @@
+/*
+ * 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.content;
+
+import android.net.Uri;
+import android.os.Parcelable;
+import android.os.Parcel;
+
+/**
+ * Contains the result of the application of a {@link ContentProviderOperation}. It is guaranteed
+ * to have exactly one of {@link #uri} or {@link #count} set.
+ */
+public class ContentProviderResult implements Parcelable {
+ public final Uri uri;
+ public final Integer count;
+
+ public ContentProviderResult(Uri uri) {
+ if (uri == null) throw new IllegalArgumentException("uri must not be null");
+ this.uri = uri;
+ this.count = null;
+ }
+
+ public ContentProviderResult(int count) {
+ this.count = count;
+ this.uri = null;
+ }
+
+ public ContentProviderResult(Parcel source) {
+ int type = source.readInt();
+ if (type == 1) {
+ count = source.readInt();
+ uri = null;
+ } else {
+ count = null;
+ uri = Uri.CREATOR.createFromParcel(source);
+ }
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ if (uri == null) {
+ dest.writeInt(1);
+ dest.writeInt(count);
+ } else {
+ dest.writeInt(2);
+ uri.writeToParcel(dest, 0);
+ }
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<ContentProviderResult> CREATOR =
+ new Creator<ContentProviderResult>() {
+ public ContentProviderResult createFromParcel(Parcel source) {
+ return new ContentProviderResult(source);
+ }
+
+ public ContentProviderResult[] newArray(int size) {
+ return new ContentProviderResult[size];
+ }
+ };
+
+ public String toString() {
+ if (uri != null) {
+ return "ContentProviderResult(uri=" + uri.toString() + ")";
+ }
+ return "ContentProviderResult(count=" + count + ")";
+ }
+} \ No newline at end of file
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 74144fc..a01c5d1 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -30,6 +30,7 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.text.TextUtils;
+import android.accounts.Account;
import android.util.Config;
import android.util.Log;
@@ -40,6 +41,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
+import java.util.ArrayList;
/**
@@ -166,6 +168,87 @@ public abstract class ContentResolver {
}
/**
+ * EntityIterator wrapper that releases the associated ContentProviderClient when the
+ * iterator is closed.
+ */
+ private class EntityIteratorWrapper implements EntityIterator {
+ private final EntityIterator mInner;
+ private final ContentProviderClient mClient;
+ private volatile boolean mClientReleased;
+
+ EntityIteratorWrapper(EntityIterator inner, ContentProviderClient client) {
+ mInner = inner;
+ mClient = client;
+ mClientReleased = false;
+ }
+
+ public boolean hasNext() throws RemoteException {
+ if (mClientReleased) {
+ throw new IllegalStateException("this iterator is already closed");
+ }
+ return mInner.hasNext();
+ }
+
+ public Entity next() throws RemoteException {
+ if (mClientReleased) {
+ throw new IllegalStateException("this iterator is already closed");
+ }
+ return mInner.next();
+ }
+
+ public void close() {
+ mClient.release();
+ mInner.close();
+ mClientReleased = true;
+ }
+
+ protected void finalize() throws Throwable {
+ if (!mClientReleased) {
+ mClient.release();
+ }
+ super.finalize();
+ }
+ }
+
+ /**
+ * Query the given URI, returning an {@link EntityIterator} over the result set.
+ *
+ * @param uri The URI, using the content:// scheme, for the content to
+ * retrieve.
+ * @param selection A filter declaring which rows to return, formatted as an
+ * SQL WHERE clause (excluding the WHERE itself). Passing null will
+ * return all rows for the given URI.
+ * @param selectionArgs You may include ?s in selection, which will be
+ * replaced by the values from selectionArgs, in the order that they
+ * appear in the selection. The values will be bound as Strings.
+ * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
+ * clause (excluding the ORDER BY itself). Passing null will use the
+ * default sort order, which may be unordered.
+ * @return An EntityIterator object
+ * @throws RemoteException thrown if a RemoteException is encountered while attempting
+ * to communicate with a remote provider.
+ * @throws IllegalArgumentException thrown if there is no provider that matches the uri
+ */
+ public final EntityIterator queryEntities(Uri uri,
+ String selection, String[] selectionArgs, String sortOrder) throws RemoteException {
+ ContentProviderClient provider = acquireContentProviderClient(uri);
+ if (provider == null) {
+ throw new IllegalArgumentException("Unknown URL " + uri);
+ }
+ try {
+ EntityIterator entityIterator =
+ provider.queryEntities(uri, selection, selectionArgs, sortOrder);
+ return new EntityIteratorWrapper(entityIterator, provider);
+ } catch(RuntimeException e) {
+ provider.release();
+ throw e;
+ } catch(RemoteException e) {
+ provider.release();
+ throw e;
+ }
+ }
+
+ /**
* Open a stream on to the content associated with a content URI. If there
* is no data associated with the URI, FileNotFoundException is thrown.
*
@@ -485,6 +568,36 @@ public abstract class ContentResolver {
}
/**
+ * Applies each of the {@link ContentProviderOperation} objects and returns an array
+ * of their results. Passes through OperationApplicationException, which may be thrown
+ * by the call to {@link ContentProviderOperation#apply}.
+ * If all the applications succeed then a {@link ContentProviderResult} array with the
+ * same number of elements as the operations will be returned. It is implementation-specific
+ * how many, if any, operations will have been successfully applied if a call to
+ * apply results in a {@link OperationApplicationException}.
+ * @param authority the authority of the ContentProvider to which this batch should be applied
+ * @param operations the operations to apply
+ * @return the results of the applications
+ * @throws OperationApplicationException thrown if an application fails.
+ * See {@link ContentProviderOperation#apply} for more information.
+ * @throws RemoteException thrown if a RemoteException is encountered while attempting
+ * to communicate with a remote provider.
+ */
+ public ContentProviderResult[] applyBatch(String authority,
+ ArrayList<ContentProviderOperation> operations)
+ throws RemoteException, OperationApplicationException {
+ ContentProviderClient provider = acquireContentProviderClient(authority);
+ if (provider == null) {
+ throw new IllegalArgumentException("Unknown authority " + authority);
+ }
+ try {
+ return provider.applyBatch(operations);
+ } finally {
+ provider.release();
+ }
+ }
+
+ /**
* Inserts multiple rows into a table at the given URL.
*
* This function make no guarantees about the atomicity of the insertions.
@@ -592,6 +705,46 @@ public abstract class ContentResolver {
}
/**
+ * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
+ * that services the content at uri, starting the provider if necessary. Returns
+ * null if there is no provider associated wih the uri. The caller must indicate that they are
+ * done with the provider by calling {@link ContentProviderClient#release} which will allow
+ * the system to release the provider it it determines that there is no other reason for
+ * keeping it active.
+ * @param uri specifies which provider should be acquired
+ * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
+ * that services the content at uri or null if there isn't one.
+ */
+ public final ContentProviderClient acquireContentProviderClient(Uri uri) {
+ IContentProvider provider = acquireProvider(uri);
+ if (provider != null) {
+ return new ContentProviderClient(this, provider);
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
+ * with the authority of name, starting the provider if necessary. Returns
+ * null if there is no provider associated wih the uri. The caller must indicate that they are
+ * done with the provider by calling {@link ContentProviderClient#release} which will allow
+ * the system to release the provider it it determines that there is no other reason for
+ * keeping it active.
+ * @param name specifies which provider should be acquired
+ * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
+ * with the authority of name or null if there isn't one.
+ */
+ public final ContentProviderClient acquireContentProviderClient(String name) {
+ IContentProvider provider = acquireProvider(name);
+ if (provider != null) {
+ return new ContentProviderClient(this, provider);
+ }
+
+ return null;
+ }
+
+ /**
* Register an observer class that gets callbacks when data identified by a
* given content URI changes.
*
@@ -694,6 +847,7 @@ public abstract class ContentResolver {
* <li>Float</li>
* <li>Double</li>
* <li>String</li>
+ * <li>Account</li>
* <li>null</li>
* </ul>
* @param extras the Bundle to check
@@ -709,6 +863,7 @@ public abstract class ContentResolver {
if (value instanceof Float) continue;
if (value instanceof Double) continue;
if (value instanceof String) continue;
+ if (value instanceof Account) continue;
throw new IllegalArgumentException("unexpected value type: "
+ value.getClass().getName());
}
diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java
index 6cd2c54..c768ffa 100644
--- a/core/java/android/content/ContentService.java
+++ b/core/java/android/content/ContentService.java
@@ -16,6 +16,7 @@
package android.content;
+import android.accounts.Account;
import android.database.IContentObserver;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
@@ -280,7 +281,7 @@ public final class ContentService extends IContentService.Stub {
}
}
- public boolean isSyncActive(String account, String authority) {
+ public boolean isSyncActive(Account account, String authority) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
long identityToken = clearCallingIdentity();
@@ -327,7 +328,7 @@ public final class ContentService extends IContentService.Stub {
return null;
}
- public boolean isAuthorityPending(String account, String authority) {
+ public boolean isAuthorityPending(Account account, String authority) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
long identityToken = clearCallingIdentity();
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ec847a4..64d8c63 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1098,6 +1098,16 @@ public abstract class Context {
public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";
/**
* Use with {@link #getSystemService} to retrieve a
+ * {@link android.accounts.AccountManager} for receiving intents at a
+ * time of your choosing.
+ * TODO STOPSHIP perform a final review of the the account apis before shipping
+ *
+ * @see #getSystemService
+ * @see android.accounts.AccountManager
+ */
+ public static final String ACCOUNT_SERVICE = "account";
+ /**
+ * Use with {@link #getSystemService} to retrieve a
* {@link android.app.ActivityManager} for interacting with the global
* system state.
*
diff --git a/core/java/android/content/Entity.aidl b/core/java/android/content/Entity.aidl
new file mode 100644
index 0000000..fb201f3
--- /dev/null
+++ b/core/java/android/content/Entity.aidl
@@ -0,0 +1,20 @@
+/* //device/java/android/android/content/Entity.aidl
+**
+** 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.
+*/
+
+package android.content;
+
+parcelable Entity;
diff --git a/core/java/android/content/Entity.java b/core/java/android/content/Entity.java
new file mode 100644
index 0000000..325dce5
--- /dev/null
+++ b/core/java/android/content/Entity.java
@@ -0,0 +1,104 @@
+/*
+ * 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.content;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.net.Uri;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+/**
+ * Objects that pass through the ContentProvider and ContentResolver's methods that deal with
+ * Entities must implement this abstract base class and thus themselves be Parcelable.
+ */
+public final class Entity implements Parcelable {
+ final private ContentValues mValues;
+ final private ArrayList<NamedContentValues> mSubValues;
+
+ public Entity(ContentValues values) {
+ mValues = values;
+ mSubValues = new ArrayList<NamedContentValues>();
+ }
+
+ public ContentValues getEntityValues() {
+ return mValues;
+ }
+
+ public ArrayList<NamedContentValues> getSubValues() {
+ return mSubValues;
+ }
+
+ public void addSubValue(Uri uri, ContentValues values) {
+ mSubValues.add(new Entity.NamedContentValues(uri, values));
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ mValues.writeToParcel(dest, 0);
+ dest.writeInt(mSubValues.size());
+ for (NamedContentValues value : mSubValues) {
+ value.uri.writeToParcel(dest, 0);
+ value.values.writeToParcel(dest, 0);
+ }
+ }
+
+ private Entity(Parcel source) {
+ mValues = ContentValues.CREATOR.createFromParcel(source);
+ final int numValues = source.readInt();
+ mSubValues = new ArrayList<NamedContentValues>(numValues);
+ for (int i = 0; i < numValues; i++) {
+ final Uri uri = Uri.CREATOR.createFromParcel(source);
+ final ContentValues values = ContentValues.CREATOR.createFromParcel(source);
+ mSubValues.add(new NamedContentValues(uri, values));
+ }
+ }
+
+ public static final Creator<Entity> CREATOR = new Creator<Entity>() {
+ public Entity createFromParcel(Parcel source) {
+ return new Entity(source);
+ }
+
+ public Entity[] newArray(int size) {
+ return new Entity[size];
+ }
+ };
+
+ public static class NamedContentValues {
+ public final Uri uri;
+ public final ContentValues values;
+
+ public NamedContentValues(Uri uri, ContentValues values) {
+ this.uri = uri;
+ this.values = values;
+ }
+ }
+
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("Entity: ").append(getEntityValues());
+ for (Entity.NamedContentValues namedValue : getSubValues()) {
+ sb.append("\n ").append(namedValue.uri);
+ sb.append("\n -> ").append(namedValue.values);
+ }
+ return sb.toString();
+ }
+}
diff --git a/core/java/android/content/EntityIterator.java b/core/java/android/content/EntityIterator.java
new file mode 100644
index 0000000..5e5f14c
--- /dev/null
+++ b/core/java/android/content/EntityIterator.java
@@ -0,0 +1,49 @@
+/*
+ * 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.content;
+
+import android.os.RemoteException;
+
+public interface EntityIterator {
+ /**
+ * Returns whether there are more elements to iterate, i.e. whether the
+ * iterator is positioned in front of an element.
+ *
+ * @return {@code true} if there are more elements, {@code false} otherwise.
+ * @see #next
+ * @since Android 1.0
+ */
+ public boolean hasNext() throws RemoteException;
+
+ /**
+ * Returns the next object in the iteration, i.e. returns the element in
+ * front of the iterator and advances the iterator by one position.
+ *
+ * @return the next object.
+ * @throws java.util.NoSuchElementException
+ * if there are no more elements.
+ * @see #hasNext
+ * @since Android 1.0
+ */
+ public Entity next() throws RemoteException;
+
+ /**
+ * Indicates that this iterator is no longer needed and that any associated resources
+ * may be released (such as a SQLite cursor).
+ */
+ public void close();
+}
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index 0606956..7e5aba5 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -28,6 +28,7 @@ import android.os.IInterface;
import android.os.ParcelFileDescriptor;
import java.io.FileNotFoundException;
+import java.util.ArrayList;
/**
* The ipc interface to talk to a content provider.
@@ -43,19 +44,25 @@ public interface IContentProvider extends IInterface {
CursorWindow window) throws RemoteException;
public Cursor query(Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder) throws RemoteException;
+ public EntityIterator queryEntities(Uri url, String selection,
+ String[] selectionArgs, String sortOrder)
+ throws RemoteException;
public String getType(Uri url) throws RemoteException;
public Uri insert(Uri url, ContentValues initialValues)
throws RemoteException;
public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException;
+ public Uri insertEntity(Uri uri, Entity entities) throws RemoteException;
public int delete(Uri url, String selection, String[] selectionArgs)
throws RemoteException;
public int update(Uri url, ContentValues values, String selection,
String[] selectionArgs) throws RemoteException;
+ public int updateEntity(Uri uri, Entity entity) throws RemoteException;
public ParcelFileDescriptor openFile(Uri url, String mode)
throws RemoteException, FileNotFoundException;
public AssetFileDescriptor openAssetFile(Uri url, String mode)
throws RemoteException, FileNotFoundException;
- public ISyncAdapter getSyncAdapter() throws RemoteException;
+ public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
+ throws RemoteException, OperationApplicationException;
/* IPC constants */
static final String descriptor = "android.content.IContentProvider";
@@ -65,8 +72,11 @@ public interface IContentProvider extends IInterface {
static final int INSERT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 2;
static final int DELETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 3;
static final int UPDATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 9;
- static final int GET_SYNC_ADAPTER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 10;
static final int BULK_INSERT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 12;
static final int OPEN_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 13;
static final int OPEN_ASSET_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 14;
+ static final int INSERT_ENTITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 16;
+ static final int UPDATE_ENTITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 17;
+ static final int QUERY_ENTITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 18;
+ static final int APPLY_BATCH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 19;
}
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index 8617d949..4352227 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -16,6 +16,7 @@
package android.content;
+import android.accounts.Account;
import android.content.ActiveSyncInfo;
import android.content.ISyncStatusObserver;
import android.content.SyncStatusInfo;
@@ -60,7 +61,7 @@ interface IContentService {
* Returns true if there is currently a sync operation for the given
* account or authority in the pending list, or actively being processed.
*/
- boolean isSyncActive(String account, String authority);
+ boolean isSyncActive(in Account account, String authority);
ActiveSyncInfo getActiveSync();
@@ -75,7 +76,7 @@ interface IContentService {
/**
* Return true if the pending status is true of any matching authorities.
*/
- boolean isAuthorityPending(String account, String authority);
+ boolean isAuthorityPending(in Account account, String authority);
void addStatusChangeListener(int mask, ISyncStatusObserver callback);
diff --git a/core/java/android/content/IEntityIterator.java b/core/java/android/content/IEntityIterator.java
new file mode 100644
index 0000000..1c478b3
--- /dev/null
+++ b/core/java/android/content/IEntityIterator.java
@@ -0,0 +1,181 @@
+/*
+ * 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.content;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * ICPC interface methods for an iterator over Entity objects.
+ * @hide
+ */
+public interface IEntityIterator extends IInterface {
+ /** Local-side IPC implementation stub class. */
+ public static abstract class Stub extends Binder implements IEntityIterator {
+ private static final String TAG = "IEntityIterator";
+ private static final java.lang.String DESCRIPTOR = "android.content.IEntityIterator";
+
+ /** Construct the stub at attach it to the interface. */
+ public Stub() {
+ this.attachInterface(this, DESCRIPTOR);
+ }
+ /**
+ * Cast an IBinder object into an IEntityIterator interface,
+ * generating a proxy if needed.
+ */
+ public static IEntityIterator asInterface(IBinder obj) {
+ if ((obj==null)) {
+ return null;
+ }
+ IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
+ if (((iin!=null)&&(iin instanceof IEntityIterator))) {
+ return ((IEntityIterator)iin);
+ }
+ return new IEntityIterator.Stub.Proxy(obj);
+ }
+
+ public IBinder asBinder() {
+ return this;
+ }
+
+ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ switch (code) {
+ case INTERFACE_TRANSACTION:
+ {
+ reply.writeString(DESCRIPTOR);
+ return true;
+ }
+
+ case TRANSACTION_hasNext:
+ {
+ data.enforceInterface(DESCRIPTOR);
+ boolean _result;
+ try {
+ _result = this.hasNext();
+ } catch (Exception e) {
+ Log.e(TAG, "caught exception in hasNext()", e);
+ reply.writeException(e);
+ return true;
+ }
+ reply.writeNoException();
+ reply.writeInt(((_result)?(1):(0)));
+ return true;
+ }
+
+ case TRANSACTION_next:
+ {
+ data.enforceInterface(DESCRIPTOR);
+ Entity entity;
+ try {
+ entity = this.next();
+ } catch (RemoteException e) {
+ Log.e(TAG, "caught exception in next()", e);
+ reply.writeException(e);
+ return true;
+ }
+ reply.writeNoException();
+ entity.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+ return true;
+ }
+
+ case TRANSACTION_close:
+ {
+ data.enforceInterface(DESCRIPTOR);
+ try {
+ this.close();
+ } catch (RemoteException e) {
+ Log.e(TAG, "caught exception in close()", e);
+ reply.writeException(e);
+ return true;
+ }
+ reply.writeNoException();
+ return true;
+ }
+ }
+ return super.onTransact(code, data, reply, flags);
+ }
+
+ private static class Proxy implements IEntityIterator {
+ private IBinder mRemote;
+ Proxy(IBinder remote) {
+ mRemote = remote;
+ }
+ public IBinder asBinder() {
+ return mRemote;
+ }
+ public java.lang.String getInterfaceDescriptor() {
+ return DESCRIPTOR;
+ }
+ public boolean hasNext() throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ boolean _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_hasNext, _data, _reply, 0);
+ _reply.readException();
+ _result = (0!=_reply.readInt());
+ }
+ finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
+
+ public Entity next() throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_next, _data, _reply, 0);
+ _reply.readException();
+ return Entity.CREATOR.createFromParcel(_reply);
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
+
+ public void close() throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_close, _data, _reply, 0);
+ _reply.readException();
+ }
+ finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
+ }
+ static final int TRANSACTION_hasNext = (IBinder.FIRST_CALL_TRANSACTION + 0);
+ static final int TRANSACTION_next = (IBinder.FIRST_CALL_TRANSACTION + 1);
+ static final int TRANSACTION_close = (IBinder.FIRST_CALL_TRANSACTION + 2);
+ }
+ public boolean hasNext() throws RemoteException;
+ public Entity next() throws RemoteException;
+ public void close() throws RemoteException;
+}
diff --git a/core/java/android/content/ISyncAdapter.aidl b/core/java/android/content/ISyncAdapter.aidl
index 671188c..d228605 100644
--- a/core/java/android/content/ISyncAdapter.aidl
+++ b/core/java/android/content/ISyncAdapter.aidl
@@ -16,6 +16,7 @@
package android.content;
+import android.accounts.Account;
import android.os.Bundle;
import android.content.ISyncContext;
@@ -33,7 +34,7 @@ oneway interface ISyncAdapter {
* @param account the account that should be synced
* @param extras SyncAdapter-specific parameters
*/
- void startSync(ISyncContext syncContext, String account, in Bundle extras);
+ void startSync(ISyncContext syncContext, in Account account, in Bundle extras);
/**
* Cancel the most recently initiated sync. Due to race conditions, this may arrive
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 24262f5..0e6be0a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1271,7 +1271,7 @@ public class Intent implements Parcelable {
* that wait until power is available to trigger.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED";
+ public static final String ACTION_POWER_CONNECTED = "android.intent.action.POWER_CONNECTED";
/**
* Broadcast Action: External power has been removed from the device.
* This is intended for applications that wish to register specifically to this notification.
@@ -1280,7 +1280,8 @@ public class Intent implements Parcelable {
* that wait until power is available to trigger.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED";
+ public static final String ACTION_POWER_DISCONNECTED =
+ "android.intent.action.POWER_DISCONNECTED";
/**
* Broadcast Action: Device is shutting down.
* This is broadcast when the device is being shut down (completely turned
@@ -1552,6 +1553,21 @@ public class Intent implements Parcelable {
public static final String ACTION_REBOOT =
"android.intent.action.REBOOT";
+ /**
+ * Broadcast Action: a remote intent is to be broadcasted.
+ *
+ * A remote intent is used for remote RPC between devices. The remote intent
+ * is serialized and sent from one device to another device. The receiving
+ * device parses the remote intent and broadcasts it. Note that anyone can
+ * broadcast a remote intent. However, if the intent receiver of the remote intent
+ * does not trust intent broadcasts from arbitrary intent senders, it should require
+ * the sender to hold certain permissions so only trusted sender's broadcast will be
+ * let through.
+ */
+ public static final String ACTION_REMOTE_INTENT =
+ "android.intent.action.REMOTE_INTENT";
+
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent categories (see addCategory()).
@@ -1810,6 +1826,13 @@ public class Intent implements Parcelable {
public static final String EXTRA_INSTALLER_PACKAGE_NAME
= "android.intent.extra.INSTALLER_PACKAGE_NAME";
+ /**
+ * Used in the extra field in the remote intent. It's astring token passed with the
+ * remote intent.
+ */
+ public static final String EXTRA_REMOTE_INTENT_TOKEN =
+ "android.intent.extra.remote_intent_token";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Intent flags (see mFlags variable).
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index e5c5dc8..365f269 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -366,6 +366,7 @@ public class IntentFilter implements Parcelable {
throws MalformedMimeTypeException {
mPriority = 0;
mActions = new ArrayList<String>();
+ addAction(action);
addDataType(dataType);
}
diff --git a/core/java/android/content/OperationApplicationException.java b/core/java/android/content/OperationApplicationException.java
new file mode 100644
index 0000000..d4101bf
--- /dev/null
+++ b/core/java/android/content/OperationApplicationException.java
@@ -0,0 +1,36 @@
+/*
+ * 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.content;
+
+/**
+ * Thrown when an application of a {@link ContentProviderOperation} fails due the specified
+ * constraints.
+ */
+public class OperationApplicationException extends Exception {
+ public OperationApplicationException() {
+ super();
+ }
+ public OperationApplicationException(String message) {
+ super(message);
+ }
+ public OperationApplicationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ public OperationApplicationException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/core/java/android/content/SyncAdapter.java b/core/java/android/content/SyncAdapter.java
index 7826e50..c658fb7 100644
--- a/core/java/android/content/SyncAdapter.java
+++ b/core/java/android/content/SyncAdapter.java
@@ -18,6 +18,7 @@ package android.content;
import android.os.Bundle;
import android.os.RemoteException;
+import android.accounts.Account;
/**
* @hide
@@ -29,7 +30,7 @@ public abstract class SyncAdapter {
public static final int LOG_SYNC_DETAILS = 2743;
class Transport extends ISyncAdapter.Stub {
- public void startSync(ISyncContext syncContext, String account,
+ public void startSync(ISyncContext syncContext, Account account,
Bundle extras) throws RemoteException {
SyncAdapter.this.startSync(new SyncContext(syncContext), account, extras);
}
@@ -42,9 +43,9 @@ public abstract class SyncAdapter {
Transport mTransport = new Transport();
/**
- * Get the Transport object. (note this is package private).
+ * Get the Transport object.
*/
- final ISyncAdapter getISyncAdapter()
+ public final ISyncAdapter getISyncAdapter()
{
return mTransport;
}
@@ -59,7 +60,7 @@ public abstract class SyncAdapter {
* @param account the account that should be synced
* @param extras SyncAdapter-specific parameters
*/
- public abstract void startSync(SyncContext syncContext, String account, Bundle extras);
+ public abstract void startSync(SyncContext syncContext, Account account, Bundle extras);
/**
* Cancel the most recently initiated sync. Due to race conditions, this may arrive
diff --git a/core/java/android/content/SyncAdapterNew.java b/core/java/android/content/SyncAdapterNew.java
new file mode 100644
index 0000000..5b23395
--- /dev/null
+++ b/core/java/android/content/SyncAdapterNew.java
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+package android.content;
+
+import android.os.*;
+import android.os.Process;
+import android.accounts.Account;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @hide
+ */
+public abstract class SyncAdapterNew {
+ private static final String TAG = "SyncAdapter";
+ private final Context mContext;
+ private final String mAuthority;
+
+ /** Kernel event log tag. Also listed in data/etc/event-log-tags. */
+ public static final int LOG_SYNC_DETAILS = 2743;
+
+ public SyncAdapterNew(Context context, String authority) {
+ mContext = context;
+ mAuthority = authority;
+ }
+
+ class Transport extends ISyncAdapter.Stub {
+ private final AtomicInteger mNumSyncStarts = new AtomicInteger(0);
+ private volatile Thread mSyncThread;
+
+ public void startSync(ISyncContext syncContext, Account account, Bundle extras) {
+ boolean alreadyInProgress;
+ synchronized (this) {
+ if (mSyncThread == null) {
+ mSyncThread = new Thread(
+ new SyncRunnable(new SyncContext(syncContext), account, extras),
+ "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet());
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ mSyncThread.start();
+ alreadyInProgress = false;
+ } else {
+ alreadyInProgress = true;
+ }
+ }
+
+ if (alreadyInProgress) {
+ try {
+ syncContext.onFinished(SyncResult.ALREADY_IN_PROGRESS);
+ } catch (RemoteException e) {
+ // don't care if the caller is no longer around
+ }
+ }
+ }
+
+ public void cancelSync() {
+ synchronized (this) {
+ if (mSyncThread != null) {
+ mSyncThread.interrupt();
+ }
+ }
+ }
+
+ private class SyncRunnable implements Runnable {
+ private final SyncContext mSyncContext;
+ private final Account mAccount;
+ private final Bundle mExtras;
+
+ private SyncRunnable(SyncContext syncContext, Account account, Bundle extras) {
+ mSyncContext = syncContext;
+ mAccount = account;
+ mExtras = extras;
+ }
+
+ public void run() {
+ if (isCanceled()) {
+ return;
+ }
+
+ SyncResult syncResult = new SyncResult();
+ ContentProviderClient provider = mAuthority != null
+ ? mContext.getContentResolver().acquireContentProviderClient(mAuthority)
+ : null;
+ try {
+ SyncAdapterNew.this.performSync(mAccount, mExtras, provider, syncResult);
+ } finally {
+ if (provider != null) {
+ provider.release();
+ }
+ if (!isCanceled()) {
+ mSyncContext.onFinished(syncResult);
+ }
+ mSyncThread = null;
+ }
+ }
+
+ private boolean isCanceled() {
+ return Thread.currentThread().isInterrupted();
+ }
+ }
+ }
+
+ Transport mTransport = new Transport();
+
+ /**
+ * Get the Transport object.
+ */
+ public final ISyncAdapter getISyncAdapter() {
+ return mTransport;
+ }
+
+ /**
+ * Perform a sync for this account. SyncAdapter-specific parameters may
+ * be specified in extras, which is guaranteed to not be null. Invocations
+ * of this method are guaranteed to be serialized.
+ *
+ * @param account the account that should be synced
+ * @param extras SyncAdapter-specific parameters
+ */
+ public abstract void performSync(Account account, Bundle extras,
+ ContentProviderClient provider, SyncResult syncResult);
+} \ No newline at end of file
diff --git a/core/java/android/content/SyncAdapterType.java b/core/java/android/content/SyncAdapterType.java
new file mode 100644
index 0000000..368a879
--- /dev/null
+++ b/core/java/android/content/SyncAdapterType.java
@@ -0,0 +1,57 @@
+/*
+ * 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.content;
+
+import android.text.TextUtils;
+
+/**
+ * Value type that represents a SyncAdapterType. This object overrides {@link #equals} and
+ * {@link #hashCode}, making it suitable for use as the key of a {@link java.util.Map}
+ */
+public class SyncAdapterType {
+ public final String authority;
+ public final String accountType;
+
+ public SyncAdapterType(String authority, String accountType) {
+ if (TextUtils.isEmpty(authority)) {
+ throw new IllegalArgumentException("the authority must not be empty: " + authority);
+ }
+ if (TextUtils.isEmpty(accountType)) {
+ throw new IllegalArgumentException("the accountType must not be empty: " + accountType);
+ }
+ this.authority = authority;
+ this.accountType = accountType;
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (!(o instanceof SyncAdapterType)) return false;
+ final SyncAdapterType other = (SyncAdapterType)o;
+ return authority.equals(other.authority) && accountType.equals(other.accountType);
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + authority.hashCode();
+ result = 31 * result + accountType.hashCode();
+ return result;
+ }
+
+ public String toString() {
+ return "SyncAdapterType {name=" + authority + ", type=" + accountType + "}";
+ }
+} \ No newline at end of file
diff --git a/core/java/android/content/SyncAdaptersCache.java b/core/java/android/content/SyncAdaptersCache.java
new file mode 100644
index 0000000..56e3e75
--- /dev/null
+++ b/core/java/android/content/SyncAdaptersCache.java
@@ -0,0 +1,77 @@
+/*
+ * 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.content;
+
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.RegisteredServicesCache;
+import android.content.res.XmlResourceParser;
+import android.content.res.TypedArray;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+import android.util.AttributeSet;
+import android.util.Xml;
+
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import com.google.android.collect.Maps;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * A cache of services that export the {@link android.content.ISyncAdapter} interface.
+ * @hide
+ */
+/* package private */ class SyncAdaptersCache extends RegisteredServicesCache<SyncAdapterType> {
+ private static final String TAG = "Account";
+
+ private static final String SERVICE_INTERFACE = "android.content.SyncAdapter";
+ private static final String SERVICE_META_DATA = "android.content.SyncAdapter";
+ private static final String ATTRIBUTES_NAME = "sync-adapter";
+
+ SyncAdaptersCache(Context context) {
+ super(context, SERVICE_INTERFACE, SERVICE_META_DATA, ATTRIBUTES_NAME);
+ }
+
+ public SyncAdapterType parseServiceAttributes(AttributeSet attrs) {
+ TypedArray sa = mContext.getResources().obtainAttributes(attrs,
+ com.android.internal.R.styleable.SyncAdapter);
+ try {
+ final String authority =
+ sa.getString(com.android.internal.R.styleable.SyncAdapter_contentAuthority);
+ final String accountType =
+ sa.getString(com.android.internal.R.styleable.SyncAdapter_accountType);
+ if (authority == null || accountType == null) {
+ return null;
+ }
+ return new SyncAdapterType(authority, accountType);
+ } finally {
+ sa.recycle();
+ }
+ }
+} \ No newline at end of file
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 4d2cce8..03cfbea 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -21,8 +21,9 @@ import com.google.android.collect.Maps;
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
-import android.accounts.AccountMonitor;
-import android.accounts.AccountMonitorListener;
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.OnAccountsUpdatedListener;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -30,8 +31,10 @@ import android.app.PendingIntent;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
-import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
+import android.content.pm.RegisteredServicesCache;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
@@ -47,7 +50,9 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.provider.Sync;
import android.provider.Settings;
+import android.provider.Sync.History;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.Time;
@@ -72,11 +77,14 @@ import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Random;
+import java.util.Observer;
+import java.util.Observable;
+import java.util.Set;
/**
* @hide
*/
-class SyncManager {
+class SyncManager implements OnAccountsUpdatedListener {
private static final String TAG = "SyncManager";
// used during dumping of the Sync history
@@ -117,14 +125,11 @@ class SyncManager {
private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarmWakeLock";
private Context mContext;
- private ContentResolver mContentResolver;
private String mStatusText = "";
private long mHeartbeatTime = 0;
- private AccountMonitor mAccountMonitor;
-
- private volatile String[] mAccounts = null;
+ private volatile Account[] mAccounts = null;
volatile private PowerManager.WakeLock mSyncWakeLock;
volatile private PowerManager.WakeLock mHandleAlarmWakeLock;
@@ -151,10 +156,11 @@ class SyncManager {
private final PendingIntent mSyncAlarmIntent;
private final PendingIntent mSyncPollAlarmIntent;
+ private final SyncAdaptersCache mSyncAdapters;
+
private BroadcastReceiver mStorageIntentReceiver =
new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
- ensureContentResolver();
String action = intent.getAction();
if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(action)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -172,6 +178,43 @@ class SyncManager {
}
};
+ private BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ if (!mFactoryTest) {
+ AccountManager.get(mContext).addOnAccountsUpdatedListener(SyncManager.this,
+ mSyncHandler, true /* updateImmediately */);
+ }
+ }
+ };
+
+ public void onAccountsUpdated(Account[] accounts) {
+ final boolean hadAccountsAlready = mAccounts != null;
+ mAccounts = accounts;
+
+ // if a sync is in progress yet it is no longer in the accounts list,
+ // cancel it
+ ActiveSyncContext activeSyncContext = mActiveSyncContext;
+ if (activeSyncContext != null) {
+ if (!ArrayUtils.contains(accounts, activeSyncContext.mSyncOperation.account)) {
+ Log.d(TAG, "canceling sync since the account has been removed");
+ sendSyncFinishedOrCanceledMessage(activeSyncContext,
+ null /* no result since this is a cancel */);
+ }
+ }
+
+ // we must do this since we don't bother scheduling alarms when
+ // the accounts are not set yet
+ sendCheckAlarmsMessage();
+
+ mSyncStorageEngine.doDatabaseCleanup(accounts);
+
+ if (hadAccountsAlready && accounts.length > 0) {
+ // request a sync so that if the password was changed we will
+ // retry any sync that failed when it was wrong
+ startSync(null /* all providers */, null /* no extras */);
+ }
+ }
+
private BroadcastReceiver mConnectivityIntentReceiver =
new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
@@ -229,7 +272,11 @@ class SyncManager {
private static final String SYNCMANAGER_PREFS_FILENAME = "/data/system/syncmanager.prefs";
+ private final boolean mFactoryTest;
+
public SyncManager(Context context, boolean factoryTest) {
+ mFactoryTest = factoryTest;
+
// Initialize the SyncStorageEngine first, before registering observers
// and creating threads and so on; it may fail if the disk is full.
SyncStorageEngine.init(context);
@@ -244,6 +291,8 @@ class SyncManager {
mPackageManager = null;
+ mSyncAdapters = new SyncAdaptersCache(mContext);
+
mSyncAlarmIntent = PendingIntent.getBroadcast(
mContext, 0 /* ignored */, new Intent(ACTION_SYNC_ALARM), 0);
@@ -253,6 +302,9 @@ class SyncManager {
IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(mConnectivityIntentReceiver, intentFilter);
+ intentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
+ context.registerReceiver(mBootCompletedReceiver, intentFilter);
+
intentFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW);
intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
context.registerReceiver(mStorageIntentReceiver, intentFilter);
@@ -288,42 +340,6 @@ class SyncManager {
sendCheckAlarmsMessage();
}
});
-
- if (!factoryTest) {
- AccountMonitorListener listener = new AccountMonitorListener() {
- public void onAccountsUpdated(String[] accounts) {
- final boolean hadAccountsAlready = mAccounts != null;
- // copy the accounts into a new array and change mAccounts to point to it
- String[] newAccounts = new String[accounts.length];
- System.arraycopy(accounts, 0, newAccounts, 0, accounts.length);
- mAccounts = newAccounts;
-
- // if a sync is in progress yet it is no longer in the accounts list, cancel it
- ActiveSyncContext activeSyncContext = mActiveSyncContext;
- if (activeSyncContext != null) {
- if (!ArrayUtils.contains(newAccounts,
- activeSyncContext.mSyncOperation.account)) {
- Log.d(TAG, "canceling sync since the account has been removed");
- sendSyncFinishedOrCanceledMessage(activeSyncContext,
- null /* no result since this is a cancel */);
- }
- }
-
- // we must do this since we don't bother scheduling alarms when
- // the accounts are not set yet
- sendCheckAlarmsMessage();
-
- mSyncStorageEngine.doDatabaseCleanup(accounts);
-
- if (hadAccountsAlready && mAccounts.length > 0) {
- // request a sync so that if the password was changed we will retry any sync
- // that failed when it was wrong
- startSync(null /* all providers */, null /* no extras */);
- }
- }
- };
- mAccountMonitor = new AccountMonitor(context, listener);
- }
}
private synchronized void initializeSyncPoll() {
@@ -452,19 +468,13 @@ class SyncManager {
return mSyncStorageEngine;
}
- private void ensureContentResolver() {
- if (mContentResolver == null) {
- mContentResolver = mContext.getContentResolver();
- }
- }
-
private void ensureAlarmService() {
if (mAlarmService == null) {
mAlarmService = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
}
}
- public String getSyncingAccount() {
+ public Account getSyncingAccount() {
ActiveSyncContext activeSyncContext = mActiveSyncContext;
return (activeSyncContext != null) ? activeSyncContext.mSyncOperation.account : null;
}
@@ -535,10 +545,10 @@ class SyncManager {
delay = -1; // this means schedule at the front of the queue
}
- String[] accounts;
- String accountFromExtras = extras.getString(ContentResolver.SYNC_EXTRAS_ACCOUNT);
- if (!TextUtils.isEmpty(accountFromExtras)) {
- accounts = new String[]{accountFromExtras};
+ Account[] accounts;
+ Account accountFromExtras = extras.getParcelable(ContentResolver.SYNC_EXTRAS_ACCOUNT);
+ if (accountFromExtras != null) {
+ accounts = new Account[]{accountFromExtras};
} else {
// if the accounts aren't configured yet then we can't support an account-less
// sync request
@@ -575,20 +585,33 @@ class SyncManager {
source = SyncStorageEngine.SOURCE_SERVER;
}
- List<String> names = new ArrayList<String>();
- List<ProviderInfo> providers = new ArrayList<ProviderInfo>();
- populateProvidersList(url, names, providers);
+ // compile a list of authorities that have sync adapters
+ // for each authority sync each account that matches a sync adapter
+ Set<String> syncableAuthorities = new HashSet<String>();
+ for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapter :
+ mSyncAdapters.getAllServices()) {
+ syncableAuthorities.add(syncAdapter.type.authority);
+ }
- final int numProviders = providers.size();
- for (int i = 0; i < numProviders; i++) {
- if (!providers.get(i).isSyncable) continue;
- final String name = names.get(i);
- for (String account : accounts) {
- scheduleSyncOperation(new SyncOperation(account, source, name, extras, delay));
- // TODO: remove this when Calendar supports multiple accounts. Until then
- // pretend that only the first account exists when syncing calendar.
- if ("calendar".equals(name)) {
- break;
+ // if the url was specified then replace the list of authorities with just this authority
+ // or clear it if this authority isn't syncable
+ if (url != null) {
+ boolean isSyncable = syncableAuthorities.contains(url.getAuthority());
+ syncableAuthorities.clear();
+ if (isSyncable) syncableAuthorities.add(url.getAuthority());
+ }
+
+ for (String authority : syncableAuthorities) {
+ for (Account account : accounts) {
+ if (mSyncAdapters.getServiceInfo(new SyncAdapterType(authority, account.mType))
+ != null) {
+ scheduleSyncOperation(
+ new SyncOperation(account, source, authority, extras, delay));
+ // TODO: remove this when Calendar supports multiple accounts. Until then
+ // pretend that only the first account exists when syncing calendar.
+ if ("calendar".equals(authority)) {
+ break;
+ }
}
}
}
@@ -598,32 +621,6 @@ class SyncManager {
mStatusText = message;
}
- private void populateProvidersList(Uri url, List<String> names, List<ProviderInfo> providers) {
- try {
- final IPackageManager packageManager = getPackageManager();
- if (url == null) {
- packageManager.querySyncProviders(names, providers);
- } else {
- final String authority = url.getAuthority();
- ProviderInfo info = packageManager.resolveContentProvider(url.getAuthority(), 0);
- if (info != null) {
- // only set this provider if the requested authority is the primary authority
- String[] providerNames = info.authority.split(";");
- if (url.getAuthority().equals(providerNames[0])) {
- names.add(authority);
- providers.add(info);
- }
- }
- }
- } catch (RemoteException ex) {
- // we should really never get this, but if we do then clear the lists, which
- // will result in the dropping of the sync request
- Log.e(TAG, "error trying to get the ProviderInfo for " + url, ex);
- names.clear();
- providers.clear();
- }
- }
-
public void scheduleLocalSync(Uri url) {
final Bundle extras = new Bundle();
extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
@@ -721,8 +718,7 @@ class SyncManager {
}
// Cap the delay
- ensureContentResolver();
- long maxSyncRetryTimeInSeconds = Settings.Gservices.getLong(mContentResolver,
+ long maxSyncRetryTimeInSeconds = Settings.Gservices.getLong(mContext.getContentResolver(),
Settings.Gservices.SYNC_MAX_RETRY_DELAY_IN_SECONDS,
DEFAULT_MAX_SYNC_RETRY_TIME_IN_SECONDS);
if (newDelayInMs > maxSyncRetryTimeInSeconds * 1000) {
@@ -857,7 +853,7 @@ class SyncManager {
* Value type that represents a sync operation.
*/
static class SyncOperation implements Comparable {
- final String account;
+ final Account account;
int syncSource;
String authority;
Bundle extras;
@@ -866,7 +862,7 @@ class SyncManager {
long delay;
SyncStorageEngine.PendingOperation pendingOperation;
- SyncOperation(String account, int source, String authority, Bundle extras, long delay) {
+ SyncOperation(Account account, int source, String authority, Bundle extras, long delay) {
this.account = account;
this.syncSource = source;
this.authority = authority;
@@ -937,21 +933,19 @@ class SyncManager {
/**
* @hide
*/
- class ActiveSyncContext extends ISyncContext.Stub {
+ class ActiveSyncContext extends ISyncContext.Stub implements ServiceConnection {
final SyncOperation mSyncOperation;
final long mHistoryRowId;
- final IContentProvider mContentProvider;
- final ISyncAdapter mSyncAdapter;
+ ISyncAdapter mSyncAdapter;
final long mStartTime;
long mTimeoutStartTime;
- public ActiveSyncContext(SyncOperation syncOperation, IContentProvider contentProvider,
- ISyncAdapter syncAdapter, long historyRowId) {
+ public ActiveSyncContext(SyncOperation syncOperation,
+ long historyRowId) {
super();
mSyncOperation = syncOperation;
mHistoryRowId = historyRowId;
- mContentProvider = contentProvider;
- mSyncAdapter = syncAdapter;
+ mSyncAdapter = null;
mStartTime = SystemClock.elapsedRealtime();
mTimeoutStartTime = mStartTime;
}
@@ -977,6 +971,37 @@ class SyncManager {
.append(", syncOperation ").append(mSyncOperation);
}
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Message msg = mSyncHandler.obtainMessage();
+ msg.what = SyncHandler.MESSAGE_SERVICE_CONNECTED;
+ msg.obj = new ServiceConnectionData(this, ISyncAdapter.Stub.asInterface(service));
+ mSyncHandler.sendMessage(msg);
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ Message msg = mSyncHandler.obtainMessage();
+ msg.what = SyncHandler.MESSAGE_SERVICE_DISCONNECTED;
+ msg.obj = new ServiceConnectionData(this, null);
+ mSyncHandler.sendMessage(msg);
+ }
+
+ boolean bindToSyncAdapter(RegisteredServicesCache.ServiceInfo info) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.d(TAG, "bindToSyncAdapter: " + info.componentName + ", connection " + this);
+ }
+ Intent intent = new Intent();
+ intent.setAction("android.content.SyncAdapter");
+ intent.setComponent(info.componentName);
+ return mContext.bindService(intent, this, Context.BIND_AUTO_CREATE);
+ }
+
+ void unBindFromSyncAdapter() {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.d(TAG, "unBindFromSyncAdapter: connection " + this);
+ }
+ mContext.unbindService(this);
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
@@ -991,6 +1016,12 @@ class SyncManager {
if (isSyncEnabled()) {
dumpSyncHistory(pw, sb);
}
+
+ pw.println();
+ pw.println("SyncAdapters:");
+ for (RegisteredServicesCache.ServiceInfo info : mSyncAdapters.getAllServices()) {
+ pw.println(" " + info);
+ }
}
static String formatTime(long time) {
@@ -1004,7 +1035,7 @@ class SyncManager {
pw.print("data connected: "); pw.println(mDataConnectionIsConnected);
pw.print("memory low: "); pw.println(mStorageIsLow);
- final String[] accounts = mAccounts;
+ final Account[] accounts = mAccounts;
pw.print("accounts: ");
if (accounts != null) {
pw.println(accounts.length);
@@ -1068,7 +1099,8 @@ class SyncManager {
for (int i=0; i<N; i++) {
SyncStorageEngine.PendingOperation op = ops.get(i);
pw.print(" #"); pw.print(i); pw.print(": account=");
- pw.print(op.account); pw.print(" authority=");
+ pw.print(op.account.mName); pw.print(":");
+ pw.print(op.account.mType); pw.print(" authority=");
pw.println(op.authority);
if (op.extras != null && op.extras.size() > 0) {
sb.setLength(0);
@@ -1078,7 +1110,7 @@ class SyncManager {
}
}
- HashSet<String> processedAccounts = new HashSet<String>();
+ HashSet<Account> processedAccounts = new HashSet<Account>();
ArrayList<SyncStatusInfo> statuses
= mSyncStorageEngine.getSyncStatus();
if (statuses != null && statuses.size() > 0) {
@@ -1090,7 +1122,7 @@ class SyncManager {
SyncStorageEngine.AuthorityInfo authority
= mSyncStorageEngine.getAuthority(status.authorityId);
if (authority != null) {
- String curAccount = authority.account;
+ Account curAccount = authority.account;
if (processedAccounts.contains(curAccount)) {
continue;
@@ -1098,8 +1130,9 @@ class SyncManager {
processedAccounts.add(curAccount);
- pw.print(" Account "); pw.print(authority.account);
- pw.println(":");
+ pw.print(" Account "); pw.print(authority.account.mName);
+ pw.print(" "); pw.print(authority.account.mType);
+ pw.println(":");
for (int j=i; j<N; j++) {
status = statuses.get(j);
authority = mSyncStorageEngine.getAuthority(status.authorityId);
@@ -1219,9 +1252,15 @@ class SyncManager {
SyncStorageEngine.AuthorityInfo authority
= mSyncStorageEngine.getAuthority(item.authorityId);
pw.print(" #"); pw.print(i+1); pw.print(": ");
- pw.print(authority != null ? authority.account : "<no account>");
- pw.print(" ");
- pw.print(authority != null ? authority.authority : "<no account>");
+ if (authority != null) {
+ pw.print(authority.account.mName);
+ pw.print(":");
+ pw.print(authority.account.mType);
+ pw.print(" ");
+ pw.print(authority.authority);
+ } else {
+ pw.print("<no account>");
+ }
Time time = new Time();
time.set(item.eventTime);
pw.print(" "); pw.print(SyncStorageEngine.SOURCES[item.source]);
@@ -1278,6 +1317,15 @@ class SyncManager {
}
}
+ class ServiceConnectionData {
+ public final ActiveSyncContext activeSyncContext;
+ public final ISyncAdapter syncAdapter;
+ ServiceConnectionData(ActiveSyncContext activeSyncContext, ISyncAdapter syncAdapter) {
+ this.activeSyncContext = activeSyncContext;
+ this.syncAdapter = syncAdapter;
+ }
+ }
+
/**
* Handles SyncOperation Messages that are posted to the associated
* HandlerThread.
@@ -1287,6 +1335,8 @@ class SyncManager {
private static final int MESSAGE_SYNC_FINISHED = 1;
private static final int MESSAGE_SYNC_ALARM = 2;
private static final int MESSAGE_CHECK_ALARMS = 3;
+ private static final int MESSAGE_SERVICE_CONNECTED = 4;
+ private static final int MESSAGE_SERVICE_DISCONNECTED = 5;
public final SyncNotificationInfo mSyncNotificationInfo = new SyncNotificationInfo();
private Long mAlarmScheduleTime = null;
@@ -1301,7 +1351,7 @@ class SyncManager {
*/
class SyncNotificationInfo {
// only valid if isActive is true
- public String account;
+ public Account account;
// only valid if isActive is true
public String authority;
@@ -1358,6 +1408,53 @@ class SyncManager {
runStateIdle();
break;
+ case SyncHandler.MESSAGE_SERVICE_CONNECTED: {
+ ServiceConnectionData msgData = (ServiceConnectionData)msg.obj;
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_CONNECTED: "
+ + msgData.activeSyncContext
+ + " active is " + mActiveSyncContext);
+ }
+ // check that this isn't an old message
+ if (mActiveSyncContext == msgData.activeSyncContext) {
+ runBoundToSyncAdapter(msgData.syncAdapter);
+ }
+ break;
+ }
+
+ case SyncHandler.MESSAGE_SERVICE_DISCONNECTED: {
+ ServiceConnectionData msgData = (ServiceConnectionData)msg.obj;
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_DISCONNECTED: "
+ + msgData.activeSyncContext
+ + " active is " + mActiveSyncContext);
+ }
+ // check that this isn't an old message
+ if (mActiveSyncContext == msgData.activeSyncContext) {
+ // cancel the sync if we have a syncadapter, which means one is
+ // outstanding
+ if (mActiveSyncContext.mSyncAdapter != null) {
+ try {
+ mActiveSyncContext.mSyncAdapter.cancelSync();
+ } catch (RemoteException e) {
+ // we don't need to retry this in this case
+ }
+ }
+
+ // pretend that the sync failed with an IOException,
+ // which is a soft error
+ SyncResult syncResult = new SyncResult();
+ syncResult.stats.numIoExceptions++;
+ runSyncFinishedOrCanceled(syncResult);
+
+ // since we are no longer syncing, check if it is time to start a new
+ // sync
+ runStateIdle();
+ }
+
+ break;
+ }
+
case SyncHandler.MESSAGE_SYNC_ALARM: {
boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
if (isLoggable) {
@@ -1456,7 +1553,7 @@ class SyncManager {
// If the accounts aren't known yet then we aren't ready to run. We will be kicked
// when the account lookup request does complete.
- String[] accounts = mAccounts;
+ Account[] accounts = mAccounts;
if (accounts == null) {
if (isLoggable) {
Log.v(TAG, "runStateIdle: accounts not known, skipping");
@@ -1542,67 +1639,68 @@ class SyncManager {
mSyncQueue.popHead();
}
- String providerName = syncOperation.authority;
- ensureContentResolver();
- IContentProvider contentProvider;
-
- // acquire the provider and update the sync history
- try {
- contentProvider = mContentResolver.acquireProvider(providerName);
- if (contentProvider == null) {
- Log.e(TAG, "Provider " + providerName + " doesn't exist");
- return;
- }
- if (contentProvider.getSyncAdapter() == null) {
- Log.e(TAG, "Provider " + providerName + " isn't syncable, " + contentProvider);
- return;
+ // connect to the sync adapter
+ SyncAdapterType syncAdapterType = new SyncAdapterType(syncOperation.authority,
+ syncOperation.account.mType);
+ RegisteredServicesCache.ServiceInfo syncAdapterInfo =
+ mSyncAdapters.getServiceInfo(syncAdapterType);
+ if (syncAdapterInfo == null) {
+ if (Config.LOGD) {
+ Log.d(TAG, "can't find a sync adapter for " + syncAdapterType);
}
- } catch (RemoteException remoteExc) {
- Log.e(TAG, "Caught a RemoteException while preparing for sync, rescheduling "
- + syncOperation, remoteExc);
- rescheduleWithDelay(syncOperation);
+ runStateIdle();
return;
- } catch (RuntimeException exc) {
- Log.e(TAG, "Caught a RuntimeException while validating sync of " + providerName,
- exc);
+ }
+
+ ActiveSyncContext activeSyncContext =
+ new ActiveSyncContext(syncOperation, insertStartSyncEvent(syncOperation));
+ mActiveSyncContext = activeSyncContext;
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "runStateIdle: setting mActiveSyncContext to " + mActiveSyncContext);
+ }
+ mSyncStorageEngine.setActiveSync(mActiveSyncContext);
+ if (!activeSyncContext.bindToSyncAdapter(syncAdapterInfo)) {
+ Log.e(TAG, "Bind attempt failed to " + syncAdapterInfo);
+ mActiveSyncContext = null;
+ mSyncStorageEngine.setActiveSync(mActiveSyncContext);
+ runStateIdle();
return;
}
- final long historyRowId = insertStartSyncEvent(syncOperation);
+ mSyncWakeLock.acquire();
+ // no need to schedule an alarm, as that will be done by our caller.
+
+ // the next step will occur when we get either a timeout or a
+ // MESSAGE_SERVICE_CONNECTED or MESSAGE_SERVICE_DISCONNECTED message
+ }
+ private void runBoundToSyncAdapter(ISyncAdapter syncAdapter) {
+ mActiveSyncContext.mSyncAdapter = syncAdapter;
+ final SyncOperation syncOperation = mActiveSyncContext.mSyncOperation;
try {
- ISyncAdapter syncAdapter = contentProvider.getSyncAdapter();
- ActiveSyncContext activeSyncContext = new ActiveSyncContext(syncOperation,
- contentProvider, syncAdapter, historyRowId);
- mSyncWakeLock.acquire();
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "starting sync of " + syncOperation);
- }
- syncAdapter.startSync(activeSyncContext, syncOperation.account,
+ syncAdapter.startSync(mActiveSyncContext, syncOperation.account,
syncOperation.extras);
- mActiveSyncContext = activeSyncContext;
- mSyncStorageEngine.setActiveSync(mActiveSyncContext);
} catch (RemoteException remoteExc) {
if (Config.LOGD) {
Log.d(TAG, "runStateIdle: caught a RemoteException, rescheduling", remoteExc);
}
+ mActiveSyncContext.unBindFromSyncAdapter();
mActiveSyncContext = null;
mSyncStorageEngine.setActiveSync(mActiveSyncContext);
rescheduleWithDelay(syncOperation);
} catch (RuntimeException exc) {
+ mActiveSyncContext.unBindFromSyncAdapter();
mActiveSyncContext = null;
mSyncStorageEngine.setActiveSync(mActiveSyncContext);
Log.e(TAG, "Caught a RuntimeException while starting the sync " + syncOperation,
exc);
}
-
- // no need to schedule an alarm, as that will be done by our caller.
}
private void runSyncFinishedOrCanceled(SyncResult syncResult) {
boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
if (isLoggable) Log.v(TAG, "runSyncFinishedOrCanceled");
- ActiveSyncContext activeSyncContext = mActiveSyncContext;
+ final ActiveSyncContext activeSyncContext = mActiveSyncContext;
mActiveSyncContext = null;
mSyncStorageEngine.setActiveSync(mActiveSyncContext);
@@ -1642,10 +1740,12 @@ class SyncManager {
Log.v(TAG, "runSyncFinishedOrCanceled: is a cancel: operation "
+ syncOperation);
}
- try {
- activeSyncContext.mSyncAdapter.cancelSync();
- } catch (RemoteException e) {
- // we don't need to retry this in this case
+ if (activeSyncContext.mSyncAdapter != null) {
+ try {
+ activeSyncContext.mSyncAdapter.cancelSync();
+ } catch (RemoteException e) {
+ // we don't need to retry this in this case
+ }
}
historyMessage = SyncStorageEngine.MESG_CANCELED;
downstreamActivity = 0;
@@ -1655,7 +1755,7 @@ class SyncManager {
stopSyncEvent(activeSyncContext.mHistoryRowId, syncOperation, historyMessage,
upstreamActivity, downstreamActivity, elapsedTime);
- mContentResolver.releaseProvider(activeSyncContext.mContentProvider);
+ activeSyncContext.unBindFromSyncAdapter();
if (syncResult != null && syncResult.tooManyDeletions) {
installHandleTooManyDeletesNotification(syncOperation.account,
@@ -1860,7 +1960,7 @@ class SyncManager {
mContext.sendBroadcast(syncStateIntent);
}
- private void installHandleTooManyDeletesNotification(String account, String authority,
+ private void installHandleTooManyDeletesNotification(Account account, String authority,
long numDeletes) {
if (mNotificationMgr == null) return;
Intent clickIntent = new Intent();
@@ -2071,7 +2171,7 @@ class SyncManager {
if (DEBUG_CHECK_DATA_CONSISTENCY) debugCheckDataStructures(true /* check the DB */);
}
- public void clear(String account, String authority) {
+ public void clear(Account account, String authority) {
Iterator<Map.Entry<String, SyncOperation>> entries = mOpsByKey.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<String, SyncOperation> entry = entries.next();
diff --git a/core/java/android/content/SyncStateContentProviderHelper.java b/core/java/android/content/SyncStateContentProviderHelper.java
index f503e6f..dc728ec 100644
--- a/core/java/android/content/SyncStateContentProviderHelper.java
+++ b/core/java/android/content/SyncStateContentProviderHelper.java
@@ -23,6 +23,7 @@ import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
+import android.accounts.Account;
/**
* Extends the schema of a ContentProvider to include the _sync_state table
@@ -43,14 +44,15 @@ public class SyncStateContentProviderHelper {
private static final Uri CONTENT_URI =
Uri.parse("content://" + SYNC_STATE_AUTHORITY + "/state");
- private static final String ACCOUNT_WHERE = "_sync_account = ?";
+ private static final String ACCOUNT_WHERE = "_sync_account = ? AND _sync_account_type = ?";
private final Provider mInternalProviderInterface;
private static final String SYNC_STATE_TABLE = "_sync_state";
- private static long DB_VERSION = 2;
+ private static long DB_VERSION = 3;
- private static final String[] ACCOUNT_PROJECTION = new String[]{"_sync_account"};
+ private static final String[] ACCOUNT_PROJECTION =
+ new String[]{"_sync_account", "_sync_account_type"};
static {
sURIMatcher.addURI(SYNC_STATE_AUTHORITY, "state", STATE);
@@ -70,8 +72,9 @@ public class SyncStateContentProviderHelper {
db.execSQL("CREATE TABLE _sync_state (" +
"_id INTEGER PRIMARY KEY," +
"_sync_account TEXT," +
+ "_sync_account_type TEXT," +
"data TEXT," +
- "UNIQUE(_sync_account)" +
+ "UNIQUE(_sync_account, _sync_account_type)" +
");");
db.execSQL("DROP TABLE IF EXISTS _sync_state_metadata");
@@ -168,15 +171,17 @@ public class SyncStateContentProviderHelper {
* @param account the account of the row that should be copied over.
*/
public void copySyncState(SQLiteDatabase dbSrc, SQLiteDatabase dbDest,
- String account) {
- final String[] whereArgs = new String[]{account};
- Cursor c = dbSrc.query(SYNC_STATE_TABLE, new String[]{"_sync_account", "data"},
+ Account account) {
+ final String[] whereArgs = new String[]{account.mName, account.mType};
+ Cursor c = dbSrc.query(SYNC_STATE_TABLE,
+ new String[]{"_sync_account", "_sync_account_type", "data"},
ACCOUNT_WHERE, whereArgs, null, null, null);
try {
if (c.moveToNext()) {
ContentValues values = new ContentValues();
values.put("_sync_account", c.getString(0));
- values.put("data", c.getBlob(1));
+ values.put("_sync_account_type", c.getString(1));
+ values.put("data", c.getBlob(2));
dbDest.replace(SYNC_STATE_TABLE, "_sync_account", values);
}
} finally {
@@ -184,14 +189,17 @@ public class SyncStateContentProviderHelper {
}
}
- public void onAccountsChanged(String[] accounts) {
+ public void onAccountsChanged(Account[] accounts) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
Cursor c = db.query(SYNC_STATE_TABLE, ACCOUNT_PROJECTION, null, null, null, null, null);
try {
while (c.moveToNext()) {
- final String account = c.getString(0);
+ final String accountName = c.getString(0);
+ final String accountType = c.getString(1);
+ Account account = new Account(accountName, accountType);
if (!ArrayUtils.contains(accounts, account)) {
- db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE, new String[]{account});
+ db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE,
+ new String[]{accountName, accountType});
}
}
} finally {
@@ -199,9 +207,9 @@ public class SyncStateContentProviderHelper {
}
}
- public void discardSyncData(SQLiteDatabase db, String account) {
+ public void discardSyncData(SQLiteDatabase db, Account account) {
if (account != null) {
- db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE, new String[]{account});
+ db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE, new String[]{account.mName, account.mType});
} else {
db.delete(SYNC_STATE_TABLE, null, null);
}
@@ -210,9 +218,9 @@ public class SyncStateContentProviderHelper {
/**
* Retrieves the SyncData bytes for the given account. The byte array returned may be null.
*/
- public byte[] readSyncDataBytes(SQLiteDatabase db, String account) {
+ public byte[] readSyncDataBytes(SQLiteDatabase db, Account account) {
Cursor c = db.query(SYNC_STATE_TABLE, null, ACCOUNT_WHERE,
- new String[]{account}, null, null, null);
+ new String[]{account.mName, account.mType}, null, null, null);
try {
if (c.moveToFirst()) {
return c.getBlob(c.getColumnIndexOrThrow("data"));
@@ -226,9 +234,10 @@ public class SyncStateContentProviderHelper {
/**
* Sets the SyncData bytes for the given account. The bytes array may be null.
*/
- public void writeSyncDataBytes(SQLiteDatabase db, String account, byte[] data) {
+ public void writeSyncDataBytes(SQLiteDatabase db, Account account, byte[] data) {
ContentValues values = new ContentValues();
values.put("data", data);
- db.update(SYNC_STATE_TABLE, values, ACCOUNT_WHERE, new String[]{account});
+ db.update(SYNC_STATE_TABLE, values, ACCOUNT_WHERE,
+ new String[]{account.mName, account.mType});
}
}
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index 9c25e73..aaa763d 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -24,6 +24,7 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
+import android.accounts.Account;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
@@ -48,6 +49,8 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.TimeZone;
+import com.google.android.collect.Sets;
+
/**
* Singleton that tracks the sync data and overall sync
* history on the device.
@@ -122,7 +125,7 @@ public class SyncStorageEngine extends Handler {
private static final long WRITE_STATISTICS_DELAY = 1000*60*30; // 1/2 hour
public static class PendingOperation {
- final String account;
+ final Account account;
final int syncSource;
final String authority;
final Bundle extras; // note: read-only.
@@ -130,7 +133,7 @@ public class SyncStorageEngine extends Handler {
int authorityId;
byte[] flatExtras;
- PendingOperation(String account, int source,
+ PendingOperation(Account account, int source,
String authority, Bundle extras) {
this.account = account;
this.syncSource = source;
@@ -149,22 +152,22 @@ public class SyncStorageEngine extends Handler {
}
static class AccountInfo {
- final String account;
+ final Account account;
final HashMap<String, AuthorityInfo> authorities =
new HashMap<String, AuthorityInfo>();
- AccountInfo(String account) {
+ AccountInfo(Account account) {
this.account = account;
}
}
public static class AuthorityInfo {
- final String account;
+ final Account account;
final String authority;
final int ident;
boolean enabled;
- AuthorityInfo(String account, String authority, int ident) {
+ AuthorityInfo(Account account, String authority, int ident) {
this.account = account;
this.authority = authority;
this.ident = ident;
@@ -200,8 +203,8 @@ public class SyncStorageEngine extends Handler {
private final SparseArray<AuthorityInfo> mAuthorities =
new SparseArray<AuthorityInfo>();
- private final HashMap<String, AccountInfo> mAccounts =
- new HashMap<String, AccountInfo>();
+ private final HashMap<Account, AccountInfo> mAccounts =
+ new HashMap<Account, AccountInfo>();
private final ArrayList<PendingOperation> mPendingOperations =
new ArrayList<PendingOperation>();
@@ -353,7 +356,7 @@ public class SyncStorageEngine extends Handler {
}
}
- public boolean getSyncProviderAutomatically(String account, String providerName) {
+ public boolean getSyncProviderAutomatically(Account account, String providerName) {
synchronized (mAuthorities) {
if (account != null) {
AuthorityInfo authority = getAuthorityLocked(account, providerName,
@@ -374,7 +377,8 @@ public class SyncStorageEngine extends Handler {
}
}
- public void setSyncProviderAutomatically(String account, String providerName, boolean sync) {
+ public void setSyncProviderAutomatically(Account account, String providerName,
+ boolean sync) {
synchronized (mAuthorities) {
if (account != null) {
AuthorityInfo authority = getAuthorityLocked(account, providerName,
@@ -412,7 +416,7 @@ public class SyncStorageEngine extends Handler {
}
}
- public AuthorityInfo getAuthority(String account, String authority) {
+ public AuthorityInfo getAuthority(Account account, String authority) {
synchronized (mAuthorities) {
return getAuthorityLocked(account, authority, null);
}
@@ -428,7 +432,7 @@ public class SyncStorageEngine extends Handler {
* Returns true if there is currently a sync operation for the given
* account or authority in the pending list, or actively being processed.
*/
- public boolean isSyncActive(String account, String authority) {
+ public boolean isSyncActive(Account account, String authority) {
synchronized (mAuthorities) {
int i = mPendingOperations.size();
while (i > 0) {
@@ -567,7 +571,7 @@ public class SyncStorageEngine extends Handler {
* Called when the set of account has changed, given the new array of
* active accounts.
*/
- public void doDatabaseCleanup(String[] accounts) {
+ public void doDatabaseCleanup(Account[] accounts) {
synchronized (mAuthorities) {
if (DEBUG) Log.w(TAG, "Updating for new accounts...");
SparseArray<AuthorityInfo> removing = new SparseArray<AuthorityInfo>();
@@ -659,7 +663,7 @@ public class SyncStorageEngine extends Handler {
/**
* Note that sync has started for the given account and authority.
*/
- public long insertStartSyncEvent(String accountName, String authorityName,
+ public long insertStartSyncEvent(Account accountName, String authorityName,
long now, int source) {
long id;
synchronized (mAuthorities) {
@@ -847,7 +851,7 @@ public class SyncStorageEngine extends Handler {
/**
* Return true if the pending status is true of any matching authorities.
*/
- public boolean isAuthorityPending(String account, String authority) {
+ public boolean isAuthorityPending(Account account, String authority) {
synchronized (mAuthorities) {
final int N = mSyncStatus.size();
for (int i=0; i<N; i++) {
@@ -944,7 +948,7 @@ public class SyncStorageEngine extends Handler {
* @param tag If non-null, this will be used in a log message if the
* requested authority does not exist.
*/
- private AuthorityInfo getAuthorityLocked(String accountName, String authorityName,
+ private AuthorityInfo getAuthorityLocked(Account accountName, String authorityName,
String tag) {
AccountInfo account = mAccounts.get(accountName);
if (account == null) {
@@ -964,7 +968,7 @@ public class SyncStorageEngine extends Handler {
return authority;
}
- private AuthorityInfo getOrCreateAuthorityLocked(String accountName,
+ private AuthorityInfo getOrCreateAuthorityLocked(Account accountName,
String authorityName, int ident, boolean doWrite) {
AccountInfo account = mAccounts.get(accountName);
if (account == null) {
@@ -1055,6 +1059,11 @@ public class SyncStorageEngine extends Handler {
if (id >= 0) {
String accountName = parser.getAttributeValue(
null, "account");
+ String accountType = parser.getAttributeValue(
+ null, "type");
+ if (accountType == null) {
+ accountType = "com.google.GAIA";
+ }
String authorityName = parser.getAttributeValue(
null, "authority");
String enabled = parser.getAttributeValue(
@@ -1066,7 +1075,8 @@ public class SyncStorageEngine extends Handler {
if (authority == null) {
if (DEBUG_FILE) Log.v(TAG, "Creating entry");
authority = getOrCreateAuthorityLocked(
- accountName, authorityName, id, false);
+ new Account(accountName, accountType),
+ authorityName, id, false);
}
if (authority != null) {
authority.enabled = enabled == null
@@ -1121,7 +1131,8 @@ public class SyncStorageEngine extends Handler {
AuthorityInfo authority = mAuthorities.get(i);
out.startTag(null, "authority");
out.attribute(null, "id", Integer.toString(authority.ident));
- out.attribute(null, "account", authority.account);
+ out.attribute(null, "account", authority.account.mName);
+ out.attribute(null, "type", authority.account.mType);
out.attribute(null, "authority", authority.authority);
if (!authority.enabled) {
out.attribute(null, "enabled", "false");
@@ -1170,6 +1181,8 @@ public class SyncStorageEngine extends Handler {
}
if (db != null) {
+ final boolean hasType = db.getVersion() >= 11;
+
// Copy in all of the status information, as well as accounts.
if (DEBUG_FILE) Log.v(TAG, "Reading legacy sync accounts db");
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
@@ -1177,6 +1190,9 @@ public class SyncStorageEngine extends Handler {
HashMap<String,String> map = new HashMap<String,String>();
map.put("_id", "status._id as _id");
map.put("account", "stats.account as account");
+ if (hasType) {
+ map.put("account_type", "stats.account_type as account_type");
+ }
map.put("authority", "stats.authority as authority");
map.put("totalElapsedTime", "totalElapsedTime");
map.put("numSyncs", "numSyncs");
@@ -1195,9 +1211,15 @@ public class SyncStorageEngine extends Handler {
Cursor c = qb.query(db, null, null, null, null, null, null);
while (c.moveToNext()) {
String accountName = c.getString(c.getColumnIndex("account"));
+ String accountType = hasType
+ ? c.getString(c.getColumnIndex("account_type")) : null;
+ if (accountType == null) {
+ accountType = "com.google.GAIA";
+ }
String authorityName = c.getString(c.getColumnIndex("authority"));
AuthorityInfo authority = this.getOrCreateAuthorityLocked(
- accountName, authorityName, -1, false);
+ new Account(accountName, accountType),
+ authorityName, -1, false);
if (authority != null) {
int i = mSyncStatus.size();
boolean found = false;
diff --git a/core/java/android/content/SyncableContentProvider.java b/core/java/android/content/SyncableContentProvider.java
index e0cd786..ab4e91c 100644
--- a/core/java/android/content/SyncableContentProvider.java
+++ b/core/java/android/content/SyncableContentProvider.java
@@ -19,6 +19,7 @@ package android.content;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
+import android.accounts.Account;
import java.util.Map;
@@ -32,6 +33,16 @@ import java.util.Map;
public abstract class SyncableContentProvider extends ContentProvider {
protected abstract boolean isTemporary();
+ private volatile TempProviderSyncAdapter mTempProviderSyncAdapter;
+
+ public void setTempProviderSyncAdapter(TempProviderSyncAdapter syncAdapter) {
+ mTempProviderSyncAdapter = syncAdapter;
+ }
+
+ public TempProviderSyncAdapter getTempProviderSyncAdapter() {
+ return mTempProviderSyncAdapter;
+ }
+
/**
* Close resources that must be closed. You must call this to properly release
* the resources used by the SyncableContentProvider.
@@ -110,7 +121,7 @@ public abstract class SyncableContentProvider extends ContentProvider {
* @param context the sync context for the operation
* @param account
*/
- public abstract void onSyncStart(SyncContext context, String account);
+ public abstract void onSyncStart(SyncContext context, Account account);
/**
* Called right after a sync is completed
@@ -124,7 +135,7 @@ public abstract class SyncableContentProvider extends ContentProvider {
* The account of the most recent call to onSyncStart()
* @return the account
*/
- public abstract String getSyncingAccount();
+ public abstract Account getSyncingAccount();
/**
* Merge diffs from a sync source with this content provider.
@@ -194,7 +205,7 @@ public abstract class SyncableContentProvider extends ContentProvider {
* Make sure that there are no entries for accounts that no longer exist
* @param accountsArray the array of currently-existing accounts
*/
- protected abstract void onAccountsChanged(String[] accountsArray);
+ protected abstract void onAccountsChanged(Account[] accountsArray);
/**
* A helper method to delete all rows whose account is not in the accounts
@@ -203,26 +214,24 @@ public abstract class SyncableContentProvider extends ContentProvider {
*
* @param accounts a map of existing accounts
* @param table the table to delete from
- * @param accountColumnName the name of the column that is expected
- * to hold the account.
*/
- protected abstract void deleteRowsForRemovedAccounts(Map<String, Boolean> accounts,
- String table, String accountColumnName);
+ protected abstract void deleteRowsForRemovedAccounts(Map<Account, Boolean> accounts,
+ String table);
/**
* Called when the sync system determines that this provider should no longer
* contain records for the specified account.
*/
- public abstract void wipeAccount(String account);
+ public abstract void wipeAccount(Account account);
/**
* Retrieves the SyncData bytes for the given account. The byte array returned may be null.
*/
- public abstract byte[] readSyncDataBytes(String account);
+ public abstract byte[] readSyncDataBytes(Account account);
/**
* Sets the SyncData bytes for the given account. The bytes array may be null.
*/
- public abstract void writeSyncDataBytes(String account, byte[] data);
+ public abstract void writeSyncDataBytes(Account account, byte[] data);
}
diff --git a/core/java/android/content/TempProviderSyncAdapter.java b/core/java/android/content/TempProviderSyncAdapter.java
index eb3a5da..0cbe01e 100644
--- a/core/java/android/content/TempProviderSyncAdapter.java
+++ b/core/java/android/content/TempProviderSyncAdapter.java
@@ -12,6 +12,7 @@ import android.util.Config;
import android.util.EventLog;
import android.util.Log;
import android.util.TimingLogger;
+import android.accounts.Account;
/**
* @hide
@@ -67,7 +68,7 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter {
* @return true, if the sync was successfully started. One reason it can
* fail to start is if there is no user configured on the device.
*/
- public abstract void onSyncStarting(SyncContext context, String account, boolean forced,
+ public abstract void onSyncStarting(SyncContext context, Account account, boolean forced,
SyncResult result);
/**
@@ -168,12 +169,12 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter {
* exist.
* @param accounts the list of accounts
*/
- public abstract void onAccountsChanged(String[] accounts);
+ public abstract void onAccountsChanged(Account[] accounts);
private Context mContext;
private class SyncThread extends Thread {
- private final String mAccount;
+ private final Account mAccount;
private final Bundle mExtras;
private final SyncContext mSyncContext;
private volatile boolean mIsCanceled = false;
@@ -181,7 +182,7 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter {
private long mInitialRxBytes;
private final SyncResult mResult;
- SyncThread(SyncContext syncContext, String account, Bundle extras) {
+ SyncThread(SyncContext syncContext, Account account, Bundle extras) {
super("SyncThread");
mAccount = account;
mExtras = extras;
@@ -221,7 +222,7 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter {
}
}
- private void sync(SyncContext syncContext, String account, Bundle extras) {
+ private void sync(SyncContext syncContext, Account account, Bundle extras) {
mIsCanceled = false;
mProviderSyncStarted = false;
@@ -273,7 +274,7 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter {
}
}
- private void runSyncLoop(SyncContext syncContext, String account, Bundle extras) {
+ private void runSyncLoop(SyncContext syncContext, Account account, Bundle extras) {
TimingLogger syncTimer = new TimingLogger(TAG + "Profiling", "sync");
syncTimer.addSplit("start");
int loopCount = 0;
@@ -518,7 +519,7 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter {
EventLog.writeEvent(SyncAdapter.LOG_SYNC_DETAILS, TAG, bytesSent, bytesReceived, "");
}
- public void startSync(SyncContext syncContext, String account, Bundle extras) {
+ public void startSync(SyncContext syncContext, Account account, Bundle extras) {
if (mSyncThread != null) {
syncContext.onFinished(SyncResult.ALREADY_IN_PROGRESS);
return;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 5f62248..9eca4a5 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -122,6 +122,7 @@ interface IPackageManager {
* providers that can sync.
* @param outInfo Filled in with a list of the ProviderInfo for each
* name in 'outNames'.
+ * @deprecated
*/
void querySyncProviders(inout List<String> outNames,
inout List<ProviderInfo> outInfo);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 6578391..88eccf7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1459,8 +1459,6 @@ public abstract class PackageManager {
* which market the package came from.
*
* @param packageName The name of the package to query
- *
- * @hide
*/
public abstract String getInstallerPackageName(String packageName);
diff --git a/core/java/android/content/pm/ProviderInfo.java b/core/java/android/content/pm/ProviderInfo.java
index b67ddf6..1d11b31 100644
--- a/core/java/android/content/pm/ProviderInfo.java
+++ b/core/java/android/content/pm/ProviderInfo.java
@@ -65,7 +65,11 @@ public final class ProviderInfo extends ComponentInfo
* running in the same process. Higher goes first. */
public int initOrder = 0;
- /** Whether or not this provider is syncable. */
+ /**
+ * Whether or not this provider is syncable.
+ * @deprecated This flag is now being ignored. The current way to make a provider
+ * syncable is to provide a SyncAdapter service for a given provider/account type.
+ */
public boolean isSyncable = false;
public ProviderInfo() {
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
new file mode 100644
index 0000000..d8f8478
--- /dev/null
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -0,0 +1,233 @@
+/*
+ * 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.content.pm;
+
+import android.content.Context;
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ComponentName;
+import android.content.res.XmlResourceParser;
+import android.util.Log;
+import android.util.AttributeSet;
+import android.util.Xml;
+
+import java.util.Map;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.io.IOException;
+
+import com.google.android.collect.Maps;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParser;
+
+/**
+ * A cache of registered services. This cache
+ * is built by interrogating the {@link PackageManager} and is updated as packages are added,
+ * removed and changed. The services are referred to by type V and
+ * are made available via the {@link #getServiceInfo} method.
+ * @hide
+ */
+public abstract class RegisteredServicesCache<V> {
+ private static final String TAG = "PackageManager";
+
+ public final Context mContext;
+ private final String mInterfaceName;
+ private final String mMetaDataName;
+ private final String mAttributesName;
+
+ // no need to be synchronized since the map is never changed once mService is written
+ private volatile Map<V, ServiceInfo<V>> mServices;
+
+ // synchronized on "this"
+ private BroadcastReceiver mReceiver = null;
+
+ public RegisteredServicesCache(Context context, String interfaceName, String metaDataName,
+ String attributeName) {
+ mContext = context;
+ mInterfaceName = interfaceName;
+ mMetaDataName = metaDataName;
+ mAttributesName = attributeName;
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+ getAllServices();
+ Map<V, ServiceInfo<V>> services = mServices;
+ fout.println("RegisteredServicesCache: " + services.size() + " services");
+ for (ServiceInfo info : services.values()) {
+ fout.println(" " + info);
+ }
+ }
+
+ private boolean maybeRegisterForPackageChanges() {
+ synchronized (this) {
+ if (mReceiver == null) {
+ synchronized (this) {
+ mReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ mServices = generateServicesMap();
+ }
+ };
+ }
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ mContext.registerReceiver(mReceiver, intentFilter);
+ return true;
+ }
+ return false;
+ }
+ }
+
+ private void maybeUnregisterForPackageChanges() {
+ synchronized (this) {
+ if (mReceiver != null) {
+ mContext.unregisterReceiver(mReceiver);
+ mReceiver = null;
+ }
+ }
+ }
+
+ /**
+ * Value type that describes a Service. The information within can be used
+ * to bind to the service.
+ */
+ public static class ServiceInfo<V> {
+ public final V type;
+ public final ComponentName componentName;
+
+ private ServiceInfo(V type, ComponentName componentName) {
+ this.type = type;
+ this.componentName = componentName;
+ }
+
+ public String toString() {
+ return "ServiceInfo: " + type + ", " + componentName;
+ }
+ }
+
+ /**
+ * Accessor for the registered authenticators.
+ * @param type the account type of the authenticator
+ * @return the AuthenticatorInfo that matches the account type or null if none is present
+ */
+ public ServiceInfo getServiceInfo(V type) {
+ if (mServices == null) {
+ maybeRegisterForPackageChanges();
+ mServices = generateServicesMap();
+ }
+ return mServices.get(type);
+ }
+
+ /**
+ * @return a collection of {@link RegisteredServicesCache.ServiceInfo} objects for all
+ * registered authenticators.
+ */
+ public Collection<ServiceInfo<V>> getAllServices() {
+ if (mServices == null) {
+ maybeRegisterForPackageChanges();
+ mServices = generateServicesMap();
+ }
+ return Collections.unmodifiableCollection(mServices.values());
+ }
+
+ /**
+ * Stops the monitoring of package additions, removals and changes.
+ */
+ public void close() {
+ maybeUnregisterForPackageChanges();
+ }
+
+ protected void finalize() throws Throwable {
+ synchronized (this) {
+ if (mReceiver != null) {
+ Log.e(TAG, "RegisteredServicesCache finalized without being closed");
+ }
+ }
+ close();
+ super.finalize();
+ }
+
+ private Map<V, ServiceInfo<V>> generateServicesMap() {
+ Map<V, ServiceInfo<V>> services = Maps.newHashMap();
+ PackageManager pm = mContext.getPackageManager();
+
+ List<ResolveInfo> resolveInfos =
+ pm.queryIntentServices(new Intent(mInterfaceName), PackageManager.GET_META_DATA);
+
+ for (ResolveInfo resolveInfo : resolveInfos) {
+ try {
+ ServiceInfo<V> info = parseServiceInfo(resolveInfo);
+ if (info != null) {
+ services.put(info.type, info);
+ } else {
+ Log.w(TAG, "Unable to load input method " + resolveInfo.toString());
+ }
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "Unable to load input method " + resolveInfo.toString(), e);
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to load input method " + resolveInfo.toString(), e);
+ }
+ }
+
+ return services;
+ }
+
+ private ServiceInfo<V> parseServiceInfo(ResolveInfo service)
+ throws XmlPullParserException, IOException {
+ android.content.pm.ServiceInfo si = service.serviceInfo;
+ ComponentName componentName = new ComponentName(si.packageName, si.name);
+
+ PackageManager pm = mContext.getPackageManager();
+
+ XmlResourceParser parser = null;
+ try {
+ parser = si.loadXmlMetaData(pm, mMetaDataName);
+ if (parser == null) {
+ throw new XmlPullParserException("No " + mMetaDataName + " meta-data");
+ }
+
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ int type;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && type != XmlPullParser.START_TAG) {
+ }
+
+ String nodeName = parser.getName();
+ if (!mAttributesName.equals(nodeName)) {
+ throw new XmlPullParserException(
+ "Meta-data does not start with " + mAttributesName + " tag");
+ }
+
+ V v = parseServiceAttributes(attrs);
+ if (v == null) {
+ return null;
+ }
+ return new ServiceInfo<V>(v, componentName);
+ } finally {
+ if (parser != null) parser.close();
+ }
+ }
+
+ public abstract V parseServiceAttributes(AttributeSet attrs);
+}
diff --git a/core/java/android/database/AbstractWindowedCursor.java b/core/java/android/database/AbstractWindowedCursor.java
index 4ac0aef..27a02e2 100644
--- a/core/java/android/database/AbstractWindowedCursor.java
+++ b/core/java/android/database/AbstractWindowedCursor.java
@@ -166,6 +166,48 @@ public abstract class AbstractWindowedCursor extends AbstractCursor
return mWindow.isBlob(mPos, columnIndex);
}
+ public boolean isString(int columnIndex)
+ {
+ checkPosition();
+
+ synchronized(mUpdatedRows) {
+ if (isFieldUpdated(columnIndex)) {
+ Object object = getUpdatedField(columnIndex);
+ return object == null || object instanceof String;
+ }
+ }
+
+ return mWindow.isString(mPos, columnIndex);
+ }
+
+ public boolean isLong(int columnIndex)
+ {
+ checkPosition();
+
+ synchronized(mUpdatedRows) {
+ if (isFieldUpdated(columnIndex)) {
+ Object object = getUpdatedField(columnIndex);
+ return object != null && (object instanceof Integer || object instanceof Long);
+ }
+ }
+
+ return mWindow.isLong(mPos, columnIndex);
+ }
+
+ public boolean isFloat(int columnIndex)
+ {
+ checkPosition();
+
+ synchronized(mUpdatedRows) {
+ if (isFieldUpdated(columnIndex)) {
+ Object object = getUpdatedField(columnIndex);
+ return object != null && (object instanceof Float || object instanceof Double);
+ }
+ }
+
+ return mWindow.isFloat(mPos, columnIndex);
+ }
+
@Override
protected void checkPosition()
{
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index 8e26730..99db81b 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -263,7 +263,58 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
}
}
+ /**
+ * Checks if a field contains a long
+ *
+ * @param row the row to read from, row - getStartPosition() being the actual row in the window
+ * @param col the column to read from
+ * @return {@code true} if given field is a long
+ */
+ public boolean isLong(int row, int col) {
+ acquireReference();
+ try {
+ return isInteger_native(row - mStartPos, col);
+ } finally {
+ releaseReference();
+ }
+ }
+
+ /**
+ * Checks if a field contains a float.
+ *
+ * @param row the row to read from, row - getStartPosition() being the actual row in the window
+ * @param col the column to read from
+ * @return {@code true} if given field is a float
+ */
+ public boolean isFloat(int row, int col) {
+ acquireReference();
+ try {
+ return isFloat_native(row - mStartPos, col);
+ } finally {
+ releaseReference();
+ }
+ }
+
+ /**
+ * Checks if a field contains either a String or is null.
+ *
+ * @param row the row to read from, row - getStartPosition() being the actual row in the window
+ * @param col the column to read from
+ * @return {@code true} if given field is {@code NULL} or a String
+ */
+ public boolean isString(int row, int col) {
+ acquireReference();
+ try {
+ return isString_native(row - mStartPos, col);
+ } finally {
+ releaseReference();
+ }
+ }
+
private native boolean isBlob_native(int row, int col);
+ private native boolean isString_native(int row, int col);
+ private native boolean isInteger_native(int row, int col);
+ private native boolean isFloat_native(int row, int col);
/**
* Returns a String for the given field.
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 10f3806..4ca6601 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -20,6 +20,7 @@ import org.apache.commons.codec.binary.Hex;
import android.content.ContentValues;
import android.content.Context;
+import android.content.OperationApplicationException;
import android.database.sqlite.SQLiteAbortException;
import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabase;
@@ -82,6 +83,8 @@ public class DatabaseUtils {
code = 8;
} else if (e instanceof SQLiteException) {
code = 9;
+ } else if (e instanceof OperationApplicationException) {
+ code = 10;
} else {
reply.writeException(e);
Log.e(TAG, "Writing exception to parcel", e);
@@ -123,6 +126,18 @@ public class DatabaseUtils {
}
}
+ public static void readExceptionWithOperationApplicationExceptionFromParcel(
+ Parcel reply) throws OperationApplicationException {
+ int code = reply.readInt();
+ if (code == 0) return;
+ String msg = reply.readString();
+ if (code == 10) {
+ throw new OperationApplicationException(msg);
+ } else {
+ DatabaseUtils.readExceptionFromParcel(reply, msg, code);
+ }
+ }
+
private static final void readExceptionFromParcel(Parcel reply, String msg, int code) {
switch (code) {
case 2:
@@ -211,7 +226,7 @@ public class DatabaseUtils {
sb.append(sqlString);
sb.append('\'');
}
-
+
/**
* SQL-escape a string.
*/
@@ -240,7 +255,7 @@ public class DatabaseUtils {
appendEscapedSQLString(sql, value.toString());
}
}
-
+
/**
* Concatenates two SQL WHERE clauses, handling empty or null values.
* @hide
@@ -252,12 +267,12 @@ public class DatabaseUtils {
if (TextUtils.isEmpty(b)) {
return a;
}
-
+
return "(" + a + ") AND (" + b + ")";
}
-
+
/**
- * return the collation key
+ * return the collation key
* @param name
* @return the collation key
*/
@@ -269,7 +284,7 @@ public class DatabaseUtils {
return "";
}
}
-
+
/**
* return the collation key in hex format
* @param name
@@ -280,7 +295,7 @@ public class DatabaseUtils {
char[] keys = Hex.encodeHex(arr);
return new String(keys, 0, getKeyLen(arr) * 2);
}
-
+
private static int getKeyLen(byte[] arr) {
if (arr[arr.length - 1] != 0) {
return arr.length;
@@ -289,16 +304,16 @@ public class DatabaseUtils {
return arr.length-1;
}
}
-
+
private static byte[] getCollationKeyInBytes(String name) {
if (mColl == null) {
mColl = Collator.getInstance();
mColl.setStrength(Collator.PRIMARY);
}
- return mColl.getCollationKey(name).toByteArray();
+ return mColl.getCollationKey(name).toByteArray();
}
-
- private static Collator mColl = null;
+
+ private static Collator mColl = null;
/**
* Prints the contents of a Cursor to System.out. The position is restored
* after printing.
@@ -591,10 +606,12 @@ public class DatabaseUtils {
public static long queryNumEntries(SQLiteDatabase db, String table) {
Cursor cursor = db.query(table, countProjection,
null, null, null, null, null);
- cursor.moveToFirst();
- long count = cursor.getLong(0);
- cursor.deactivate();
- return count;
+ try {
+ cursor.moveToFirst();
+ return cursor.getLong(0);
+ } finally {
+ cursor.close();
+ }
}
/**
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index 8a63919..af54a71 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -355,23 +355,26 @@ public class SQLiteQueryBuilder
String groupBy, String having, String sortOrder, String limit) {
String[] projection = computeProjection(projectionIn);
+ StringBuilder where = new StringBuilder();
+
if (mWhereClause.length() > 0) {
- mWhereClause.append(')');
+ where.append(mWhereClause.toString());
+ where.append(')');
}
// Tack on the user's selection, if present.
if (selection != null && selection.length() > 0) {
if (mWhereClause.length() > 0) {
- mWhereClause.append(" AND ");
+ where.append(" AND ");
}
- mWhereClause.append('(');
- mWhereClause.append(selection);
- mWhereClause.append(')');
+ where.append('(');
+ where.append(selection);
+ where.append(')');
}
return buildQueryString(
- mDistinct, mTables, projection, mWhereClause.toString(),
+ mDistinct, mTables, projection, where.toString(),
groupBy, having, sortOrder, limit);
}
diff --git a/core/java/android/net/WebAddress.java b/core/java/android/net/WebAddress.java
index f4a2a6a..f6159de 100644
--- a/core/java/android/net/WebAddress.java
+++ b/core/java/android/net/WebAddress.java
@@ -54,7 +54,7 @@ public class WebAddress {
static Pattern sAddressPattern = Pattern.compile(
/* scheme */ "(?:(http|HTTP|https|HTTPS|file|FILE)\\:\\/\\/)?" +
/* authority */ "(?:([-A-Za-z0-9$_.+!*'(),;?&=]+(?:\\:[-A-Za-z0-9$_.+!*'(),;?&=]+)?)@)?" +
- /* host */ "([-A-Za-z0-9%]+(?:\\.[-A-Za-z0-9%]+)*)?" +
+ /* host */ "([-A-Za-z0-9%_]+(?:\\.[-A-Za-z0-9%_]+)*)?" +
/* port */ "(?:\\:([0-9]+))?" +
/* path */ "(\\/?.*)?");
diff --git a/core/java/android/net/http/Request.java b/core/java/android/net/http/Request.java
index df4fff0..aeb85a2 100644
--- a/core/java/android/net/http/Request.java
+++ b/core/java/android/net/http/Request.java
@@ -116,12 +116,17 @@ class Request {
mBodyProvider = bodyProvider;
mBodyLength = bodyLength;
- if (bodyProvider == null) {
+ if (bodyProvider == null && !"POST".equalsIgnoreCase(method)) {
mHttpRequest = new BasicHttpRequest(method, getUri());
} else {
mHttpRequest = new BasicHttpEntityEnclosingRequest(
method, getUri());
- setBodyProvider(bodyProvider, bodyLength);
+ // it is ok to have null entity for BasicHttpEntityEnclosingRequest.
+ // By using BasicHttpEntityEnclosingRequest, it will set up the
+ // correct content-length, content-type and content-encoding.
+ if (bodyProvider != null) {
+ setBodyProvider(bodyProvider, bodyLength);
+ }
}
addHeader(HOST_HEADER, getHostPort());
diff --git a/core/java/android/net/http/RequestQueue.java b/core/java/android/net/http/RequestQueue.java
index 66d5722..54a1cce 100644
--- a/core/java/android/net/http/RequestQueue.java
+++ b/core/java/android/net/http/RequestQueue.java
@@ -52,10 +52,44 @@ public class RequestQueue implements RequestFeeder {
private Context mContext;
+ private static class RequestSet {
+ private final LinkedList<Request> mHighPriority;
+ private final LinkedList<Request> mLowPriority;
+
+ RequestSet() {
+ mHighPriority = new LinkedList<Request>();
+ mLowPriority = new LinkedList<Request>();
+ }
+
+ void add(Request req, boolean head) {
+ LinkedList l = mLowPriority;
+ if (req.mHighPriority) {
+ l = mHighPriority;
+ }
+ if (head) {
+ l.addFirst(req);
+ } else {
+ l.add(req);
+ }
+ }
+
+ Request removeFirst() {
+ if (!mHighPriority.isEmpty()) {
+ return mHighPriority.removeFirst();
+ } else if (!mLowPriority.isEmpty()) {
+ return mLowPriority.removeFirst();
+ }
+ return null;
+ }
+
+ boolean isEmpty() {
+ return mHighPriority.isEmpty() && mLowPriority.isEmpty();
+ }
+ };
/**
* Requests, indexed by HttpHost (scheme, host, port)
*/
- private LinkedHashMap<HttpHost, LinkedList<Request>> mPending;
+ private LinkedHashMap<HttpHost, RequestSet> mPending;
/* Support for notifying a client when queue is empty */
private boolean mClientWaiting = false;
@@ -344,7 +378,7 @@ public class RequestQueue implements RequestFeeder {
public RequestQueue(Context context, int connectionCount) {
mContext = context;
- mPending = new LinkedHashMap<HttpHost, LinkedList<Request>>(32);
+ mPending = new LinkedHashMap<HttpHost, RequestSet>(32);
mActivePool = new ActivePool(connectionCount);
mActivePool.startup();
@@ -480,7 +514,7 @@ public class RequestQueue implements RequestFeeder {
req = new Request(method, httpHost, mProxyHost, uri.mPath, bodyProvider,
bodyLength, eventHandler, headers, highPriority);
- queueRequest(req, highPriority);
+ queueRequest(req, false);
mActivePool.mTotalRequest++;
@@ -520,19 +554,24 @@ public class RequestQueue implements RequestFeeder {
HttpLog.v("dump()");
StringBuilder dump = new StringBuilder();
int count = 0;
- Iterator<Map.Entry<HttpHost, LinkedList<Request>>> iter;
+ Iterator<Map.Entry<HttpHost, RequestSet>> iter;
// mActivePool.log(dump);
if (!mPending.isEmpty()) {
iter = mPending.entrySet().iterator();
while (iter.hasNext()) {
- Map.Entry<HttpHost, LinkedList<Request>> entry = iter.next();
+ Map.Entry<HttpHost, RequestSet> entry = iter.next();
String hostName = entry.getKey().getHostName();
StringBuilder line = new StringBuilder("p" + count++ + " " + hostName + " ");
- LinkedList<Request> reqList = entry.getValue();
- ListIterator reqIter = reqList.listIterator(0);
+ RequestSet reqList = entry.getValue();
+ ListIterator reqIter = reqList.mHighPriority.listIterator(0);
+ while (iter.hasNext()) {
+ Request request = (Request)iter.next();
+ line.append(request + " ");
+ }
+ reqIter = reqList.mLowPriority.listIterator(0);
while (iter.hasNext()) {
Request request = (Request)iter.next();
line.append(request + " ");
@@ -564,7 +603,7 @@ public class RequestQueue implements RequestFeeder {
Request ret = null;
if (mNetworkConnected && mPending.containsKey(host)) {
- LinkedList<Request> reqList = mPending.get(host);
+ RequestSet reqList = mPending.get(host);
ret = reqList.removeFirst();
if (reqList.isEmpty()) {
mPending.remove(host);
@@ -597,18 +636,14 @@ public class RequestQueue implements RequestFeeder {
protected synchronized void queueRequest(Request request, boolean head) {
HttpHost host = request.mProxyHost == null ? request.mHost : request.mProxyHost;
- LinkedList<Request> reqList;
+ RequestSet reqList;
if (mPending.containsKey(host)) {
reqList = mPending.get(host);
} else {
- reqList = new LinkedList<Request>();
+ reqList = new RequestSet();
mPending.put(host, reqList);
}
- if (head) {
- reqList.addFirst(request);
- } else {
- reqList.add(request);
- }
+ reqList.add(request, head);
}
@@ -621,12 +656,12 @@ public class RequestQueue implements RequestFeeder {
}
/* helper */
- private Request removeFirst(LinkedHashMap<HttpHost, LinkedList<Request>> requestQueue) {
+ private Request removeFirst(LinkedHashMap<HttpHost, RequestSet> requestQueue) {
Request ret = null;
- Iterator<Map.Entry<HttpHost, LinkedList<Request>>> iter = requestQueue.entrySet().iterator();
+ Iterator<Map.Entry<HttpHost, RequestSet>> iter = requestQueue.entrySet().iterator();
if (iter.hasNext()) {
- Map.Entry<HttpHost, LinkedList<Request>> entry = iter.next();
- LinkedList<Request> reqList = entry.getValue();
+ Map.Entry<HttpHost, RequestSet> entry = iter.next();
+ RequestSet reqList = entry.getValue();
ret = reqList.removeFirst();
if (reqList.isEmpty()) {
requestQueue.remove(entry.getKey());
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 8fcb4d7..d9612af 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -647,6 +647,25 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
public static final native int getBinderDeathObjectCount();
/**
+ * Primes the register map cache.
+ *
+ * Only works for classes in the bootstrap class loader. Does not
+ * cause classes to be loaded if they're not already present.
+ *
+ * The classAndMethodDesc argument is a concatentation of the VM-internal
+ * class descriptor, method name, and method descriptor. Examples:
+ * Landroid/os/Looper;.loop:()V
+ * Landroid/app/ActivityThread;.main:([Ljava/lang/String;)V
+ *
+ * @param classAndMethodDesc the method to prepare
+ *
+ * @hide
+ */
+ public static final boolean cacheRegisterMap(String classAndMethodDesc) {
+ return VMDebug.cacheRegisterMap(classAndMethodDesc);
+ }
+
+ /**
* API for gathering and querying instruction counts.
*
* Example usage:
diff --git a/core/java/android/os/Exec.java b/core/java/android/os/Exec.java
deleted file mode 100644
index a50d5fe..0000000
--- a/core/java/android/os/Exec.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.
- */
-
-package android.os;
-
-import java.io.FileDescriptor;
-
-/**
- * @hide
- * Tools for executing commands. Not for public consumption.
- */
-
-public class Exec
-{
- /**
- * @param cmd The command to execute
- * @param arg0 The first argument to the command, may be null
- * @param arg1 the second argument to the command, may be null
- * @return the file descriptor of the started process.
- *
- */
- public static FileDescriptor createSubprocess(
- String cmd, String arg0, String arg1) {
- return createSubprocess(cmd, arg0, arg1, null);
- }
-
- /**
- * @param cmd The command to execute
- * @param arg0 The first argument to the command, may be null
- * @param arg1 the second argument to the command, may be null
- * @param processId A one-element array to which the process ID of the
- * started process will be written.
- * @return the file descriptor of the started process.
- *
- */
- public static native FileDescriptor createSubprocess(
- String cmd, String arg0, String arg1, int[] processId);
-
- public static native void setPtyWindowSize(FileDescriptor fd,
- int row, int col, int xpixel, int ypixel);
- /**
- * Causes the calling thread to wait for the process associated with the
- * receiver to finish executing.
- *
- * @return The exit value of the Process being waited on
- *
- */
- public static native int waitFor(int processId);
-}
-
diff --git a/core/java/android/os/LatencyTimer.java b/core/java/android/os/LatencyTimer.java
new file mode 100644
index 0000000..ed2f0f9e
--- /dev/null
+++ b/core/java/android/os/LatencyTimer.java
@@ -0,0 +1,94 @@
+/*
+ * 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.os;
+
+import android.util.Log;
+
+import java.util.HashMap;
+
+/**
+ * A class to help with measuring latency in your code.
+ *
+ * Suggested usage:
+ * 1) Instanciate a LatencyTimer as a class field.
+ * private [static] LatencyTimer mLt = new LatencyTimer(100, 1000);
+ * 2) At various points in the code call sample with a string and the time delta to some fixed time.
+ * The string should be unique at each point of the code you are measuring.
+ * mLt.sample("before processing event", System.nanoTime() - event.getEventTimeNano());
+ * processEvent(event);
+ * mLt.sample("after processing event ", System.nanoTime() - event.getEventTimeNano());
+ *
+ * @hide
+ */
+public final class LatencyTimer
+{
+ final String TAG = "LatencyTimer";
+ final int mSampleSize;
+ final int mScaleFactor;
+ volatile HashMap<String, long[]> store = new HashMap<String, long[]>();
+
+ /**
+ * Creates a LatencyTimer object
+ * @param sampleSize number of samples to collect before printing out the average
+ * @param scaleFactor divisor used to make each sample smaller to prevent overflow when
+ * (sampleSize * average sample value)/scaleFactor > Long.MAX_VALUE
+ */
+ public LatencyTimer(int sampleSize, int scaleFactor) {
+ if (scaleFactor == 0) {
+ scaleFactor = 1;
+ }
+ mScaleFactor = scaleFactor;
+ mSampleSize = sampleSize;
+ }
+
+ /**
+ * Add a sample delay for averaging.
+ * @param tag string used for printing out the result. This should be unique at each point of
+ * this called.
+ * @param delta time difference from an unique point of reference for a particular iteration
+ */
+ public void sample(String tag, long delta) {
+ long[] array = getArray(tag);
+
+ // array[mSampleSize] holds the number of used entries
+ final int index = (int) array[mSampleSize]++;
+ array[index] = delta;
+ if (array[mSampleSize] == mSampleSize) {
+ long totalDelta = 0;
+ for (long d : array) {
+ totalDelta += d/mScaleFactor;
+ }
+ array[mSampleSize] = 0;
+ Log.i(TAG, tag + " average = " + totalDelta / mSampleSize);
+ }
+ }
+
+ private long[] getArray(String tag) {
+ long[] data = store.get(tag);
+ if (data == null) {
+ synchronized(store) {
+ data = store.get(tag);
+ if (data == null) {
+ data = new long[mSampleSize + 1];
+ store.put(tag, data);
+ data[mSampleSize] = 0;
+ }
+ }
+ }
+ return data;
+ }
+}
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index 23c0a7b..5ab305e 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -22,7 +22,7 @@ import java.util.HashMap;
* Takes care of the grunt work of maintaining a list of remote interfaces,
* typically for the use of performing callbacks from a
* {@link android.app.Service} to its clients. In particular, this:
- *
+ *
* <ul>
* <li> Keeps track of a set of registered {@link IInterface} callbacks,
* taking care to identify them through their underlying unique {@link IBinder}
@@ -34,13 +34,13 @@ import java.util.HashMap;
* multithreaded incoming calls, and a thread-safe way to iterate over a
* snapshot of the list without holding its lock.
* </ul>
- *
+ *
* <p>To use this class, simply create a single instance along with your
* service, and call its {@link #register} and {@link #unregister} methods
* as client register and unregister with your service. To call back on to
* the registered clients, use {@link #beginBroadcast},
* {@link #getBroadcastItem}, and {@link #finishBroadcast}.
- *
+ *
* <p>If a registered callback's process goes away, this class will take
* care of automatically removing it from the list. If you want to do
* additional work in this situation, you can create a subclass that
@@ -51,7 +51,7 @@ public class RemoteCallbackList<E extends IInterface> {
= new HashMap<IBinder, Callback>();
private Object[] mActiveBroadcast;
private boolean mKilled = false;
-
+
private final class Callback implements IBinder.DeathRecipient {
final E mCallback;
final Object mCookie;
@@ -60,7 +60,7 @@ public class RemoteCallbackList<E extends IInterface> {
mCallback = callback;
mCookie = cookie;
}
-
+
public void binderDied() {
synchronized (mCallbacks) {
mCallbacks.remove(mCallback.asBinder());
@@ -68,7 +68,7 @@ public class RemoteCallbackList<E extends IInterface> {
onCallbackDied(mCallback, mCookie);
}
}
-
+
/**
* Simple version of {@link RemoteCallbackList#register(E, Object)}
* that does not take a cookie object.
@@ -85,19 +85,20 @@ public class RemoteCallbackList<E extends IInterface> {
* object is already in the list), then it will be left as-is.
* Registrations are not counted; a single call to {@link #unregister}
* will remove a callback after any number calls to register it.
- *
+ *
* @param callback The callback interface to be added to the list. Must
* not be null -- passing null here will cause a NullPointerException.
* Most services will want to check for null before calling this with
* an object given from a client, so that clients can't crash the
* service with bad data.
+ *
* @param cookie Optional additional data to be associated with this
* callback.
*
* @return Returns true if the callback was successfully added to the list.
* Returns false if it was not added, either because {@link #kill} had
* previously been called or the callback's process has gone away.
- *
+ *
* @see #unregister
* @see #kill
* @see #onCallbackDied
@@ -118,7 +119,7 @@ public class RemoteCallbackList<E extends IInterface> {
}
}
}
-
+
/**
* Remove from the list a callback that was previously added with
* {@link #register}. This uses the
@@ -126,14 +127,14 @@ public class RemoteCallbackList<E extends IInterface> {
* find the previous registration.
* Registrations are not counted; a single unregister call will remove
* a callback after any number calls to {@link #register} for it.
- *
+ *
* @param callback The callback to be removed from the list. Passing
* null here will cause a NullPointerException, so you will generally want
* to check for null before calling.
- *
+ *
* @return Returns true if the callback was found and unregistered. Returns
* false if the given callback was not found on the list.
- *
+ *
* @see #register
*/
public boolean unregister(E callback) {
@@ -146,13 +147,13 @@ public class RemoteCallbackList<E extends IInterface> {
return false;
}
}
-
+
/**
* Disable this callback list. All registered callbacks are unregistered,
* and the list is disabled so that future calls to {@link #register} will
* fail. This should be used when a Service is stopping, to prevent clients
* from registering callbacks after it is stopped.
- *
+ *
* @see #register
*/
public void kill() {
@@ -164,7 +165,7 @@ public class RemoteCallbackList<E extends IInterface> {
mKilled = true;
}
}
-
+
/**
* Old version of {@link #onCallbackDied(E, Object)} that
* does not provide a cookie.
@@ -189,7 +190,7 @@ public class RemoteCallbackList<E extends IInterface> {
public void onCallbackDied(E callback, Object cookie) {
onCallbackDied(callback);
}
-
+
/**
* Prepare to start making calls to the currently registered callbacks.
* This creates a copy of the callback list, which you can retrieve items
@@ -198,12 +199,12 @@ public class RemoteCallbackList<E extends IInterface> {
* same thread (usually by scheduling with {@link Handler} or
* do your own synchronization. You must call {@link #finishBroadcast}
* when done.
- *
+ *
* <p>A typical loop delivering a broadcast looks like this:
- *
+ *
* <pre>
* final int N = callbacks.beginBroadcast();
- * for (int i=0; i<N; i++) {
+ * for (int i=0; i&lt;N; i++) {
* try {
* callbacks.getBroadcastItem(i).somethingHappened();
* } catch (RemoteException e) {
@@ -212,11 +213,11 @@ public class RemoteCallbackList<E extends IInterface> {
* }
* }
* callbacks.finishBroadcast();</pre>
- *
+ *
* @return Returns the number of callbacks in the broadcast, to be used
* with {@link #getBroadcastItem} to determine the range of indices you
* can supply.
- *
+ *
* @see #getBroadcastItem
* @see #finishBroadcast
*/
@@ -237,26 +238,26 @@ public class RemoteCallbackList<E extends IInterface> {
return i;
}
}
-
+
/**
* Retrieve an item in the active broadcast that was previously started
* with {@link #beginBroadcast}. This can <em>only</em> be called after
* the broadcast is started, and its data is no longer valid after
* calling {@link #finishBroadcast}.
- *
+ *
* <p>Note that it is possible for the process of one of the returned
* callbacks to go away before you call it, so you will need to catch
* {@link RemoteException} when calling on to the returned object.
* The callback list itself, however, will take care of unregistering
* these objects once it detects that it is no longer valid, so you can
* handle such an exception by simply ignoring it.
- *
+ *
* @param index Which of the registered callbacks you would like to
* retrieve. Ranges from 0 to 1-{@link #beginBroadcast}.
- *
+ *
* @return Returns the callback interface that you can call. This will
* always be non-null.
- *
+ *
* @see #beginBroadcast
*/
public E getBroadcastItem(int index) {
@@ -272,12 +273,12 @@ public class RemoteCallbackList<E extends IInterface> {
public Object getBroadcastCookie(int index) {
return ((Callback)mActiveBroadcast[index]).mCookie;
}
-
+
/**
* Clean up the state of a broadcast previously initiated by calling
* {@link #beginBroadcast}. This must always be called when you are done
* with a broadcast.
- *
+ *
* @see #beginBroadcast
*/
public void finishBroadcast() {
diff --git a/core/java/android/preference/RingtonePreference.java b/core/java/android/preference/RingtonePreference.java
index 6beb06d..b46f180 100644
--- a/core/java/android/preference/RingtonePreference.java
+++ b/core/java/android/preference/RingtonePreference.java
@@ -31,8 +31,9 @@ import android.util.Log;
* The chosen ringtone's URI will be persisted as a string.
* <p>
* If the user chooses the "Default" item, the saved string will be one of
- * {@link System#DEFAULT_RINGTONE_URI} or
- * {@link System#DEFAULT_NOTIFICATION_URI}. If the user chooses the "Silent"
+ * {@link System#DEFAULT_RINGTONE_URI},
+ * {@link System#DEFAULT_NOTIFICATION_URI}, or
+ * {@link System#DEFAULT_ALARM_ALERT_URI}. If the user chooses the "Silent"
* item, the saved string will be an empty string.
*
* @attr ref android.R.styleable#RingtonePreference_ringtoneType
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index 20702a1..abdcd93 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -22,6 +22,7 @@ import android.database.ContentObserver;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.media.AudioManager;
+import android.net.Uri;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.provider.Settings;
@@ -147,10 +148,16 @@ public class VolumePreference extends SeekBarPreference implements
System.getUriFor(System.VOLUME_SETTINGS[mStreamType]),
false, mVolumeObserver);
- mRingtone = RingtoneManager.getRingtone(mContext,
- mStreamType == AudioManager.STREAM_NOTIFICATION
- ? Settings.System.DEFAULT_NOTIFICATION_URI
- : Settings.System.DEFAULT_RINGTONE_URI);
+ Uri defaultUri = null;
+ if (mStreamType == AudioManager.STREAM_RING) {
+ defaultUri = Settings.System.DEFAULT_RINGTONE_URI;
+ } else if (mStreamType == AudioManager.STREAM_NOTIFICATION) {
+ defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI;
+ } else {
+ defaultUri = Settings.System.DEFAULT_ALARM_ALERT_URI;
+ }
+
+ mRingtone = RingtoneManager.getRingtone(mContext, defaultUri);
mRingtone.setStreamType(mStreamType);
}
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 4a709f6..3a221e4 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -32,6 +32,7 @@ import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.Config;
import android.util.Log;
+import android.accounts.Account;
import com.android.internal.database.ArrayListCursor;
import com.google.android.gdata.client.AndroidGDataClient;
import com.google.android.gdata.client.AndroidXmlParserFactory;
@@ -157,11 +158,12 @@ public final class Calendar {
* @param account the account whose rows should be deleted
* @return the count of rows that were deleted
*/
- public static int deleteCalendarsForAccount(ContentResolver cr,
- String account) {
+ public static int deleteCalendarsForAccount(ContentResolver cr, Account account) {
// delete all calendars that match this account
- return Calendar.Calendars.delete(cr, Calendar.Calendars._SYNC_ACCOUNT + "=?",
- new String[] {account});
+ return Calendar.Calendars.delete(cr,
+ Calendar.Calendars._SYNC_ACCOUNT + "=? AND "
+ + Calendar.Calendars._SYNC_ACCOUNT_TYPE + "=?",
+ new String[] {account.mName, account.mType});
}
/**
diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java
index 84fe184..0829cfb 100644
--- a/core/java/android/provider/Contacts.java
+++ b/core/java/android/provider/Contacts.java
@@ -30,6 +30,7 @@ import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import android.widget.ImageView;
+import android.accounts.Account;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
@@ -75,6 +76,12 @@ public class Contacts {
public static final String _SYNC_ACCOUNT = "_sync_account";
/**
+ * The _SYNC_ACCOUNT_TYPE to which this setting corresponds. This may be null.
+ * <P>Type: TEXT</P>
+ */
+ public static final String _SYNC_ACCOUNT_TYPE = "_sync_account_type";
+
+ /**
* The key of this setting.
* <P>Type: TEXT</P>
*/
@@ -134,6 +141,7 @@ public class Contacts {
selectString = (account == null)
? "_sync_account is null AND key=?"
: "_sync_account=? AND key=?";
+// : "_sync_account=? AND _sync_account_type=? AND key=?";
selectArgs = (account == null)
? new String[]{key}
: new String[]{account, key};
@@ -158,7 +166,8 @@ public class Contacts {
// the account name is, so we're using a global setting for SYNC_EVERYTHING.
// Some day when we add multiple accounts to the UI this should honor the account
// that was asked for.
- //values.put(_SYNC_ACCOUNT, account);
+ //values.put(_SYNC_ACCOUNT, account.mName);
+ //values.put(_SYNC_ACCOUNT_TYPE, account.mType);
values.put(KEY, key);
values.put(VALUE, value);
cr.update(Settings.CONTENT_URI, values, null, null);
@@ -846,6 +855,12 @@ public class Contacts {
public static final String GROUP_SYNC_ACCOUNT = "group_sync_account";
/**
+ * The account type of the group.
+ * <P>Type: TEXT</P>
+ */
+ public static final String GROUP_SYNC_ACCOUNT_TYPE = "group_sync_account_type";
+
+ /**
* The row id of the person.
* <P>Type: TEXT</P>
*/
@@ -1022,13 +1037,7 @@ public class Contacts {
}
} else {
if (!TextUtils.isEmpty(label)) {
- if (label.toString().equals(MOBILE_EMAIL_TYPE_NAME)) {
- display =
- context.getString(
- com.android.internal.R.string.mobileEmailTypeName);
- } else {
- display = label;
- }
+ display = label;
}
}
break;
@@ -1229,7 +1238,7 @@ public class Contacts {
*/
public interface OrganizationColumns {
/**
- * The type of the the phone number.
+ * The type of the organizations.
* <P>Type: INTEGER (one of the constants below)</P>
*/
public static final String TYPE = "type";
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
new file mode 100644
index 0000000..f32ab00
--- /dev/null
+++ b/core/java/android/provider/ContactsContract.java
@@ -0,0 +1,805 @@
+/*
+ * 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.provider;
+
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+
+/**
+ * The contract between the contacts provider and applications. Contains definitions
+ * for the supported URIs and columns.
+ *
+ * @hide
+ */
+public final class ContactsContract {
+ /** The authority for the contacts provider */
+ public static final String AUTHORITY = "com.android.contacts";
+ /** A content:// style uri to the authority for the contacts provider */
+ public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
+
+ public interface AccountsColumns {
+ /**
+ * The name of this account data
+ * <P>Type: TEXT</P>
+ */
+ public static final String NAME = "name";
+ /**
+ * The name of this account data
+ * <P>Type: TEXT</P>
+ */
+ public static final String TYPE = "type";
+ /**
+ * The name of this account data
+ * <P>Type: TEXT</P>
+ */
+ public static final String DATA1 = "data1";
+
+ /**
+ * The value for this account data
+ * <P>Type: INTEGER</P>
+ */
+ public static final String DATA2 = "data2";
+
+ /**
+ * The value for this account data
+ * <P>Type: INTEGER</P>
+ */
+ public static final String DATA3 = "data3";
+
+ /**
+ * The value for this account data
+ * <P>Type: INTEGER</P>
+ */
+ public static final String DATA4 = "data4";
+
+ /**
+ * The value for this account data
+ * <P>Type: INTEGER</P>
+ */
+ public static final String DATA5 = "data5";
+ }
+
+ /**
+ * Constants for the aggregates table, which contains a record per group
+ * of contact representing the same person.
+ */
+ public static final class Accounts implements BaseColumns, AccountsColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Accounts() {}
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "accounts");
+
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of
+ * account data.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contacts_account";
+
+ /**
+ * The MIME type of a {@link #CONTENT_URI} subdirectory of a account
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contacts_account";
+ }
+
+ public interface AggregatesColumns {
+ /**
+ * The display name for the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String DISPLAY_NAME = "display_name";
+
+ /**
+ * The number of times a person has been contacted
+ * <P>Type: INTEGER</P>
+ */
+ public static final String TIMES_CONTACTED = "times_contacted";
+
+ /**
+ * The last time a person was contacted.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String LAST_TIME_CONTACTED = "last_time_contacted";
+
+ /**
+ * Is the contact starred?
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String STARRED = "starred";
+
+ /**
+ * Reference to the row in the data table holding the primary phone number.
+ * <P>Type: INTEGER REFERENCES data(_id)</P>
+ */
+ public static final String PRIMARY_PHONE_ID = "primary_phone_id";
+
+ /**
+ * Reference to the row in the data table holding the primary email address.
+ * <P>Type: INTEGER REFERENCES data(_id)</P>
+ */
+ public static final String PRIMARY_EMAIL_ID = "primary_email_id";
+
+ /**
+ * Reference to the row in the data table holding the photo.
+ * <P>Type: INTEGER REFERENCES data(_id)</P>
+ */
+ public static final String PHOTO_ID = "photo_id";
+
+ /**
+ * Reference to a row containing custom ringtone and send to voicemail information.
+ * <P>Type: INTEGER REFERENCES data(_id)</P>
+ */
+ public static final String CUSTOM_RINGTONE_ID = "custom_ringtone_id";
+ }
+
+ /**
+ * Constants for the aggregates table, which contains a record per group
+ * of contact representing the same person.
+ */
+ public static final class Aggregates implements BaseColumns, AggregatesColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Aggregates() {}
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "aggregates");
+
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of
+ * people.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/person_aggregate";
+
+ /**
+ * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
+ * person.
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/person_aggregate";
+
+ /**
+ * A sub-directory of a single contact aggregate that contains all of their
+ * {@link Data} rows.
+ */
+ public static final class Data implements BaseColumns, DataColumns {
+ /**
+ * no public constructor since this is a utility class
+ */
+ private Data() {}
+
+ /**
+ * The directory twig for this sub-table
+ */
+ public static final String CONTENT_DIRECTORY = "data";
+ }
+ }
+
+
+ /**
+ * Constants for the contacts table, which contains the base contact information.
+ */
+ public static final class Contacts implements BaseColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Contacts() {}
+
+ /**
+ * A reference to the {@link Accounts#_ID} that this data belongs to.
+ */
+ public static final String ACCOUNTS_ID = "accounts_id";
+
+ /**
+ * A reference to the {@link Aggregates#_ID} that this data belongs to.
+ */
+ public static final String AGGREGATE_ID = "aggregate_id";
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "contacts");
+
+ /**
+ * The content:// style URL for filtering people by email address. The
+ * filter argument should be passed as an additional path segment after
+ * this URI.
+ *
+ * @hide
+ */
+ public static final Uri CONTENT_FILTER_EMAIL_URI = Uri.withAppendedPath(CONTENT_URI, "filter_email");
+
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of
+ * people.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/person";
+
+ /**
+ * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
+ * person.
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/person";
+
+ /**
+ * A string that uniquely identifies this contact to its source, which is referred to
+ * by the {@link #ACCOUNTS_ID}
+ */
+ public static final String SOURCE_ID = "sourceid";
+
+ /**
+ * An integer that is updated whenever this contact or its data changes.
+ */
+ public static final String VERSION = "version";
+
+ /**
+ * Set to 1 whenever the version changes
+ */
+ public static final String DIRTY = "dirty";
+
+ /**
+ * A sub-directory of a single contact that contains all of their {@link Data} rows.
+ * To access this directory append
+ */
+ public static final class Data implements BaseColumns, DataColumns {
+ /**
+ * no public constructor since this is a utility class
+ */
+ private Data() {}
+
+ /**
+ * The directory twig for this sub-table
+ */
+ public static final String CONTENT_DIRECTORY = "data";
+ }
+ }
+
+ private interface DataColumns {
+ /**
+ * The package name that defines this type of data.
+ */
+ public static final String PACKAGE = "package";
+
+ /**
+ * The mime-type of the item represented by this row.
+ */
+ public static final String MIMETYPE = "mimetype";
+
+ /**
+ * A reference to the {@link android.provider.ContactsContract.Contacts#_ID}
+ * that this data belongs to.
+ */
+ public static final String CONTACT_ID = "contact_id";
+
+ /**
+ * Whether this is the primary entry of its kind for the contact it belongs to
+ * <P>Type: INTEGER (if set, non-0 means true)</P>
+ */
+ public static final String IS_PRIMARY = "is_primary";
+
+ /**
+ * Whether this is the primary entry of its kind for the aggregate it belongs to. Any data
+ * record that is "super primary" must also be "primary".
+ * <P>Type: INTEGER (if set, non-0 means true)</P>
+ */
+ public static final String IS_SUPER_PRIMARY = "is_super_primary";
+
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA1 = "data1";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA2 = "data2";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA3 = "data3";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA4 = "data4";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA5 = "data5";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA6 = "data6";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA7 = "data7";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA8 = "data8";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA9 = "data9";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA10 = "data10";
+ }
+
+ /**
+ * Constants for the data table, which contains data points tied to a contact.
+ * For example, a phone number or email address. Each row in this table contains a type
+ * definition and some generic columns. Each data type can define the meaning for each of
+ * the generic columns.
+ */
+ public static final class Data implements BaseColumns, DataColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Data() {}
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "data");
+
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of data.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/data";
+ }
+
+ /**
+ * A table that represents the result of looking up a phone number, for example for caller ID.
+ * The table joins that data row for the phone number with the contact that owns the number.
+ * To perform a lookup you must append the number you want to find to {@link #CONTENT_URI}.
+ */
+ public static final class PhoneLookup implements BaseColumns, DataColumns, AggregatesColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private PhoneLookup() {}
+
+ /**
+ * The content:// style URI for this table. Append the phone number you want to lookup
+ * to this URI and query it to perform a lookup. For example:
+ *
+ * {@code
+ * Uri lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_URI, phoneNumber);
+ * }
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "phone_lookup");
+ }
+
+ /**
+ * Container for definitions of common data types stored in the {@link Data} table.
+ */
+ public static final class CommonDataKinds {
+ /**
+ * The {@link Data#PACKAGE} value for common data that should be shown
+ * using a default style.
+ */
+ public static final String PACKAGE_COMMON = "common";
+
+ /**
+ * Columns common across the specific types.
+ */
+ private interface BaseCommonColumns {
+ /**
+ * The package name that defines this type of data.
+ */
+ public static final String PACKAGE = "package";
+
+ /**
+ * The mime-type of the item represented by this row.
+ */
+ public static final String MIMETYPE = "mimetype";
+
+ /**
+ * A reference to the {@link android.provider.ContactsContract.Contacts#_ID} that this
+ * data belongs to.
+ */
+ public static final String CONTACT_ID = "contact_id";
+ }
+
+ /**
+ * Columns common across the specific types.
+ */
+ private interface CommonColumns {
+ /**
+ * The type of data, for example Home or Work.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String TYPE = "data1";
+
+ /**
+ * The data for the contact method.
+ * <P>Type: TEXT</P>
+ */
+ public static final String DATA = "data2";
+
+ /**
+ * The user defined label for the the contact method.
+ * <P>Type: TEXT</P>
+ */
+ public static final String LABEL = "data3";
+ }
+
+ /**
+ * Parts of the name.
+ */
+ public static final class StructuredName {
+ private StructuredName() {}
+
+ /** Mime-type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/name";
+
+ /**
+ * The given name for the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String GIVEN_NAME = "data1";
+
+ /**
+ * The family name for the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String FAMILY_NAME = "data2";
+
+ /**
+ * The contact's honorific prefix, e.g. "Sir"
+ * <P>Type: TEXT</P>
+ */
+ public static final String PREFIX = "data3";
+
+ /**
+ * The contact's middle name
+ * <P>Type: TEXT</P>
+ */
+ public static final String MIDDLE_NAME = "data4";
+
+ /**
+ * The contact's honorific suffix, e.g. "Jr"
+ */
+ public static final String SUFFIX = "data5";
+
+ /**
+ * The phonetic version of the given name for the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String PHONETIC_GIVEN_NAME = "data6";
+
+ /**
+ * The phonetic version of the additional name for the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String PHONETIC_MIDDLE_NAME = "data7";
+
+ /**
+ * The phonetic version of the family name for the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String PHONETIC_FAMILY_NAME = "data8";
+
+ /**
+ * The name that should be used to display the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String DISPLAY_NAME = "data9";
+ }
+
+ /**
+ * A nickname.
+ */
+ public static final class Nickname {
+ private Nickname() {}
+
+ /** Mime-type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/nickname";
+
+ /**
+ * The type of data, for example Home or Work.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String TYPE = "data1";
+
+ public static final int TYPE_CUSTOM = 1;
+ public static final int TYPE_DEFAULT = 2;
+ public static final int TYPE_OTHER_NAME = 3;
+ public static final int TYPE_MAINDEN_NAME = 4;
+ public static final int TYPE_SHORT_NAME = 5;
+ public static final int TYPE_INITIALS = 6;
+
+ /**
+ * The name itself
+ */
+ public static final String NAME = "data2";
+
+ /**
+ * The user provided label, only used if TYPE is {@link #TYPE_CUSTOM}.
+ * <P>Type: TEXT</P>
+ */
+ public static final String LABEL = "data3";
+ }
+
+ /**
+ * Common data definition for telephone numbers.
+ */
+ public static final class Phone implements BaseCommonColumns, CommonColumns {
+ private Phone() {}
+
+ /** Mime-type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone";
+
+ public static final int TYPE_CUSTOM = 0;
+ public static final int TYPE_HOME = 1;
+ public static final int TYPE_MOBILE = 2;
+ public static final int TYPE_WORK = 3;
+ public static final int TYPE_FAX_WORK = 4;
+ public static final int TYPE_FAX_HOME = 5;
+ public static final int TYPE_PAGER = 6;
+ public static final int TYPE_OTHER = 7;
+
+ /**
+ * The phone number as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String NUMBER = "data2";
+ }
+
+ /**
+ * Common data definition for email addresses.
+ */
+ public static final class Email implements BaseCommonColumns, CommonColumns {
+ private Email() {}
+
+ /** Mime-type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/email";
+
+ public static final int TYPE_CUSTOM = 0;
+ public static final int TYPE_HOME = 1;
+ public static final int TYPE_WORK = 2;
+ public static final int TYPE_OTHER = 3;
+ }
+
+ /**
+ * Common data definition for postal addresses.
+ */
+ public static final class Postal implements BaseCommonColumns, CommonColumns {
+ private Postal() {}
+
+ /** Mime-type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/postal-address";
+
+ public static final int TYPE_CUSTOM = 0;
+ public static final int TYPE_HOME = 1;
+ public static final int TYPE_WORK = 2;
+ public static final int TYPE_OTHER = 3;
+ }
+
+ /**
+ * Common data definition for IM addresses.
+ */
+ public static final class Im implements BaseCommonColumns, CommonColumns {
+ private Im() {}
+
+ /** Mime-type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/im";
+
+ public static final int TYPE_CUSTOM = 0;
+ public static final int TYPE_HOME = 1;
+ public static final int TYPE_WORK = 2;
+ public static final int TYPE_OTHER = 3;
+
+ public static final String PROTOCOL = "data5";
+
+ /**
+ * The predefined IM protocol types. The protocol can either be non-present, one
+ * of these types, or a free-form string. These cases are encoded in the PROTOCOL
+ * column as:
+ * <ul>
+ * <li>null</li>
+ * <li>pre:&lt;an integer, one of the protocols below&gt;</li>
+ * <li>custom:&lt;a string&gt;</li>
+ * </ul>
+ */
+ public static final int PROTOCOL_AIM = 0;
+ public static final int PROTOCOL_MSN = 1;
+ public static final int PROTOCOL_YAHOO = 2;
+ public static final int PROTOCOL_SKYPE = 3;
+ public static final int PROTOCOL_QQ = 4;
+ public static final int PROTOCOL_GOOGLE_TALK = 5;
+ public static final int PROTOCOL_ICQ = 6;
+ public static final int PROTOCOL_JABBER = 7;
+
+ public static String encodePredefinedImProtocol(int protocol) {
+ return "pre:" + protocol;
+ }
+
+ public static String encodeCustomImProtocol(String protocolString) {
+ return "custom:" + protocolString;
+ }
+
+ public static Object decodeImProtocol(String encodedString) {
+ if (encodedString == null) {
+ return null;
+ }
+
+ if (encodedString.startsWith("pre:")) {
+ return Integer.parseInt(encodedString.substring(4));
+ }
+
+ if (encodedString.startsWith("custom:")) {
+ return encodedString.substring(7);
+ }
+
+ throw new IllegalArgumentException(
+ "the value is not a valid encoded protocol, " + encodedString);
+ }
+ }
+
+ /**
+ * Common data definition for organizations.
+ */
+ public static final class Organization implements BaseCommonColumns {
+ private Organization() {}
+
+ /** Mime-type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/organization";
+
+ /**
+ * The type of data, for example Home or Work.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String TYPE = "data1";
+
+ public static final int TYPE_CUSTOM = 0;
+ public static final int TYPE_HOME = 1;
+ public static final int TYPE_WORK = 2;
+ public static final int TYPE_OTHER = 3;
+
+ /**
+ * The user provided label, only used if TYPE is {@link #TYPE_CUSTOM}.
+ * <P>Type: TEXT</P>
+ */
+ public static final String LABEL = "data2";
+
+ /**
+ * The company as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String COMPANY = "data3";
+
+ /**
+ * The position title at this company as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String TITLE = "data4";
+ }
+
+ /**
+ * Photo of the contact.
+ */
+ public static final class Photo implements BaseCommonColumns {
+ private Photo() {}
+
+ /** Mime-type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/photo";
+
+ /**
+ * Thumbnail photo of the contact. This is the raw bytes of an image
+ * that could be inflated using {@link BitmapFactory}.
+ * <p>
+ * Type: BLOB
+ */
+ public static final String PHOTO = "data1";
+ }
+
+ /**
+ * Notes about the contact.
+ */
+ public static final class Note implements BaseCommonColumns {
+ private Note() {}
+
+ /** Mime-type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/note";
+
+ /**
+ * The note text.
+ * <P>Type: TEXT</P>
+ */
+ public static final String NOTE = "data1";
+ }
+
+ /**
+ * Custom ringtone associated with the contact.
+ */
+ public static final class CustomRingtone implements BaseCommonColumns {
+ private CustomRingtone() {}
+
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/custom_ringtone";
+
+ /**
+ * Whether to send the number to voicemail.
+ * <P>Type: INTEGER (if set, non-0 means true)</P>
+ */
+ public static final String SEND_TO_VOICEMAIL = "data1";
+
+ /**
+ * The ringtone uri.
+ * <P>Type: TEXT</P>
+ */
+ public static final String RINGTONE_URI = "data2";
+ }
+
+ /**
+ * Group Membership.
+ */
+ public static final class GroupMembership implements BaseCommonColumns {
+ private GroupMembership() {}
+
+ /** Mime-type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE =
+ "vnd.android.cursor.item/group_membership";
+
+ /**
+ * The row id of the group that this group membership refers to. Either this or the
+ * GROUP_SOURCE_ID must be set. If they are both set then they must refer to the same
+ * group.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String GROUP_ROW_ID = "data1";
+
+ /**
+ * The source id of the group that this membership refers to. Either this or the
+ * GROUP_ROW_ID must be set. If they are both set then they must refer to the same
+ * group.
+ * <P>Type: STRING</P>
+ */
+ public static final String GROUP_SOURCE_ID = "data2";
+ }
+ }
+
+ /**
+ * Constants for the contact aggregation exceptions table, which contains
+ * aggregation rules overriding those used by automatic aggregation.
+ */
+ public static final class AggregationExceptions {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private AggregationExceptions() {}
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI =
+ Uri.withAppendedPath(AUTHORITY_URI, "aggregation_exceptions");
+
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of data.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/aggregation_exception";
+
+ /**
+ * The type of exception: {@link #TYPE_NEVER_MATCH} or {@link #TYPE_ALWAYS_MATCH}.
+ *
+ * <P>Type: INTEGER</P>
+ */
+ public static final String TYPE = "type";
+
+ public static final int TYPE_NEVER_MATCH = 0;
+ public static final int TYPE_ALWAYS_MATCH = 1;
+
+ /**
+ * A reference to the {@link android.provider.ContactsContract.Contacts#_ID} of one of
+ * the contacts that the rule applies to.
+ */
+ public static final String CONTACT_ID1 = "contact_id1";
+
+ /**
+ * A reference to the {@link android.provider.ContactsContract.Contacts#_ID} of the other
+ * contact that the rule applies to.
+ */
+ public static final String CONTACT_ID2 = "contact_id2";
+ }
+}
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 4c58e0d..790fe5c 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -63,7 +63,7 @@ public final class Downloads implements BaseColumns {
* that had initiated a download when that download completes. The
* download's content: uri is specified in the intent's data.
*/
- public static final String DOWNLOAD_COMPLETED_ACTION =
+ public static final String ACTION_DOWNLOAD_COMPLETED =
"android.intent.action.DOWNLOAD_COMPLETED";
/**
@@ -76,7 +76,7 @@ public final class Downloads implements BaseColumns {
* Note: this is not currently sent for downloads that have completed
* successfully.
*/
- public static final String NOTIFICATION_CLICKED_ACTION =
+ public static final String ACTION_NOTIFICATION_CLICKED =
"android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED";
/**
@@ -84,14 +84,14 @@ public final class Downloads implements BaseColumns {
* <P>Type: TEXT</P>
* <P>Owner can Init/Read</P>
*/
- public static final String URI = "uri";
+ public static final String COLUMN_URI = "uri";
/**
* The name of the column containing application-specific data.
* <P>Type: TEXT</P>
* <P>Owner can Init/Read/Write</P>
*/
- public static final String APP_DATA = "entity";
+ public static final String COLUMN_APP_DATA = "entity";
/**
* The name of the column containing the flags that indicates whether
@@ -104,7 +104,7 @@ public final class Downloads implements BaseColumns {
* <P>Type: BOOLEAN</P>
* <P>Owner can Init</P>
*/
- public static final String NO_INTEGRITY = "no_integrity";
+ public static final String COLUMN_NO_INTEGRITY = "no_integrity";
/**
* The name of the column containing the filename that the initiating
@@ -113,7 +113,7 @@ public final class Downloads implements BaseColumns {
* <P>Type: TEXT</P>
* <P>Owner can Init</P>
*/
- public static final String FILENAME_HINT = "hint";
+ public static final String COLUMN_FILE_NAME_HINT = "hint";
/**
* The name of the column containing the filename where the downloaded data
@@ -128,7 +128,7 @@ public final class Downloads implements BaseColumns {
* <P>Type: TEXT</P>
* <P>Owner can Init/Read</P>
*/
- public static final String MIMETYPE = "mimetype";
+ public static final String COLUMN_MIME_TYPE = "mimetype";
/**
* The name of the column containing the flag that controls the destination
@@ -136,7 +136,7 @@ public final class Downloads implements BaseColumns {
* <P>Type: INTEGER</P>
* <P>Owner can Init</P>
*/
- public static final String DESTINATION = "destination";
+ public static final String COLUMN_DESTINATION = "destination";
/**
* The name of the column containing the flags that controls whether the
@@ -145,7 +145,7 @@ public final class Downloads implements BaseColumns {
* <P>Type: INTEGER</P>
* <P>Owner can Init/Read/Write</P>
*/
- public static final String VISIBILITY = "visibility";
+ public static final String COLUMN_VISIBILITY = "visibility";
/**
* The name of the column containing the current control state of the download.
@@ -154,7 +154,7 @@ public final class Downloads implements BaseColumns {
* <P>Type: INTEGER</P>
* <P>Owner can Read</P>
*/
- public static final String CONTROL = "control";
+ public static final String COLUMN_CONTROL = "control";
/**
* The name of the column containing the current status of the download.
@@ -163,7 +163,7 @@ public final class Downloads implements BaseColumns {
* <P>Type: INTEGER</P>
* <P>Owner can Read</P>
*/
- public static final String STATUS = "status";
+ public static final String COLUMN_STATUS = "status";
/**
* The name of the column containing the date at which some interesting
@@ -172,7 +172,7 @@ public final class Downloads implements BaseColumns {
* <P>Type: BIGINT</P>
* <P>Owner can Read</P>
*/
- public static final String LAST_MODIFICATION = "lastmod";
+ public static final String COLUMN_LAST_MODIFICATION = "lastmod";
/**
* The name of the column containing the package name of the application
@@ -181,7 +181,7 @@ public final class Downloads implements BaseColumns {
* <P>Type: TEXT</P>
* <P>Owner can Init/Read</P>
*/
- public static final String NOTIFICATION_PACKAGE = "notificationpackage";
+ public static final String COLUMN_NOTIFICATION_PACKAGE = "notificationpackage";
/**
* The name of the column containing the component name of the class that
@@ -191,7 +191,7 @@ public final class Downloads implements BaseColumns {
* <P>Type: TEXT</P>
* <P>Owner can Init/Read</P>
*/
- public static final String NOTIFICATION_CLASS = "notificationclass";
+ public static final String COLUMN_NOTIFICATION_CLASS = "notificationclass";
/**
* If extras are specified when requesting a download they will be provided in the intent that
@@ -199,7 +199,7 @@ public final class Downloads implements BaseColumns {
* <P>Type: TEXT</P>
* <P>Owner can Init</P>
*/
- public static final String NOTIFICATION_EXTRAS = "notificationextras";
+ public static final String COLUMN_NOTIFICATION_EXTRAS = "notificationextras";
/**
* The name of the column contain the values of the cookie to be used for
@@ -208,7 +208,7 @@ public final class Downloads implements BaseColumns {
* <P>Type: TEXT</P>
* <P>Owner can Init</P>
*/
- public static final String COOKIE_DATA = "cookiedata";
+ public static final String COLUMN_COOKIE_DATA = "cookiedata";
/**
* The name of the column containing the user agent that the initiating
@@ -216,7 +216,7 @@ public final class Downloads implements BaseColumns {
* <P>Type: TEXT</P>
* <P>Owner can Init</P>
*/
- public static final String USER_AGENT = "useragent";
+ public static final String COLUMN_USER_AGENT = "useragent";
/**
* The name of the column containing the referer (sic) that the initiating
@@ -224,7 +224,7 @@ public final class Downloads implements BaseColumns {
* <P>Type: TEXT</P>
* <P>Owner can Init</P>
*/
- public static final String REFERER = "referer";
+ public static final String COLUMN_REFERER = "referer";
/**
* The name of the column containing the total size of the file being
@@ -232,7 +232,7 @@ public final class Downloads implements BaseColumns {
* <P>Type: INTEGER</P>
* <P>Owner can Read</P>
*/
- public static final String TOTAL_BYTES = "total_bytes";
+ public static final String COLUMN_TOTAL_BYTES = "total_bytes";
/**
* The name of the column containing the size of the part of the file that
@@ -240,7 +240,7 @@ public final class Downloads implements BaseColumns {
* <P>Type: INTEGER</P>
* <P>Owner can Read</P>
*/
- public static final String CURRENT_BYTES = "current_bytes";
+ public static final String COLUMN_CURRENT_BYTES = "current_bytes";
/**
* The name of the column where the initiating application can provide the
@@ -252,7 +252,7 @@ public final class Downloads implements BaseColumns {
* <P>Type: INTEGER</P>
* <P>Owner can Init</P>
*/
- public static final String OTHER_UID = "otheruid";
+ public static final String COLUMN_OTHER_UID = "otheruid";
/**
* The name of the column where the initiating application can provided the
@@ -261,7 +261,7 @@ public final class Downloads implements BaseColumns {
* <P>Type: TEXT</P>
* <P>Owner can Init/Read/Write</P>
*/
- public static final String TITLE = "title";
+ public static final String COLUMN_TITLE = "title";
/**
* The name of the column where the initiating application can provide the
@@ -270,7 +270,7 @@ public final class Downloads implements BaseColumns {
* <P>Type: TEXT</P>
* <P>Owner can Init/Read/Write</P>
*/
- public static final String DESCRIPTION = "description";
+ public static final String COLUMN_DESCRIPTION = "description";
/*
* Lists the destinations that an application can specify for a download.
diff --git a/core/java/android/provider/Im.java b/core/java/android/provider/Im.java
index 19ad158..c36f508 100644
--- a/core/java/android/provider/Im.java
+++ b/core/java/android/provider/Im.java
@@ -871,14 +871,22 @@ public class Im {
}
/**
- * The common columns for both one-to-one chat messages or group chat messages.
+ * The common columns for messages table
*/
- public interface BaseMessageColumns {
+ public interface MessageColumns {
/**
- * The user this message belongs to
- * <P>Type: TEXT</P>
+ * The thread_id column stores the contact id of the contact the message belongs to.
+ * For groupchat messages, the thread_id stores the group id, which is the contact id
+ * of the temporary group contact created for the groupchat. So there should be no
+ * collision between groupchat message thread id and regular message thread id.
*/
- String CONTACT = "contact";
+ String THREAD_ID = "thread_id";
+
+ /**
+ * The nickname. This is used for groupchat messages to indicate the participant's
+ * nickname. For non groupchat messages, this field should be left empty.
+ */
+ String NICKNAME = "nickname";
/**
* The body
@@ -917,68 +925,193 @@ public class Im {
* <P>Type: STRING</P>
*/
String PACKET_ID = "packet_id";
- }
-
- /**
- * Columns from the Messages table.
- */
- public interface MessagesColumns extends BaseMessageColumns{
- /**
- * The provider id
- * <P> Type: INTEGER </P>
- */
- String PROVIDER = "provider";
/**
- * The account id
- * <P> Type: INTEGER </P>
+ * Is groupchat message or not
+ * <P>Type: INTEGER</P>
*/
- String ACCOUNT = "account";
+ String IS_GROUP_CHAT = "is_muc";
}
/**
* This table contains messages.
*/
- public static final class Messages implements BaseColumns, MessagesColumns {
+ public static final class Messages implements BaseColumns, MessageColumns {
/**
* no public constructor since this is a utility class
*/
private Messages() {}
/**
- * Gets the Uri to query messages by contact.
+ * Gets the Uri to query messages by thread id.
+ *
+ * @param threadId the thread id of the message.
+ * @return the Uri
+ */
+ public static final Uri getContentUriByThreadId(long threadId) {
+ Uri.Builder builder = CONTENT_URI_MESSAGES_BY_THREAD_ID.buildUpon();
+ ContentUris.appendId(builder, threadId);
+ return builder.build();
+ }
+
+ /**
+ * @deprecated
+ *
+ * Gets the Uri to query messages by account and contact.
*
- * @param providerId the provider id of the contact.
* @param accountId the account id of the contact.
* @param username the user name of the contact.
* @return the Uri
*/
- public static final Uri getContentUriByContact(long providerId,
- long accountId, String username) {
- Uri.Builder builder = CONTENT_URI_MESSAGES_BY.buildUpon();
+ public static final Uri getContentUriByContact(long accountId, String username) {
+ Uri.Builder builder = CONTENT_URI_MESSAGES_BY_ACCOUNT_AND_CONTACT.buildUpon();
+ ContentUris.appendId(builder, accountId);
+ builder.appendPath(username);
+ return builder.build();
+ }
+
+ /**
+ * Gets the Uri to query messages by provider.
+ *
+ * @param providerId the service provider id.
+ * @return the Uri
+ */
+ public static final Uri getContentUriByProvider(long providerId) {
+ Uri.Builder builder = CONTENT_URI_MESSAGES_BY_PROVIDER.buildUpon();
ContentUris.appendId(builder, providerId);
+ return builder.build();
+ }
+
+ /**
+ * Gets the Uri to query off the record messages by account.
+ *
+ * @param accountId the account id.
+ * @return the Uri
+ */
+ public static final Uri getContentUriByAccount(long accountId) {
+ Uri.Builder builder = CONTENT_URI_BY_ACCOUNT.buildUpon();
+ ContentUris.appendId(builder, accountId);
+ return builder.build();
+ }
+
+ /**
+ * Gets the Uri to query off the record messages by thread id.
+ *
+ * @param threadId the thread id of the message.
+ * @return the Uri
+ */
+ public static final Uri getOtrMessagesContentUriByThreadId(long threadId) {
+ Uri.Builder builder = OTR_MESSAGES_CONTENT_URI_BY_THREAD_ID.buildUpon();
+ ContentUris.appendId(builder, threadId);
+ return builder.build();
+ }
+
+ /**
+ * @deprecated
+ *
+ * Gets the Uri to query off the record messages by account and contact.
+ *
+ * @param accountId the account id of the contact.
+ * @param username the user name of the contact.
+ * @return the Uri
+ */
+ public static final Uri getOtrMessagesContentUriByContact(long accountId, String username) {
+ Uri.Builder builder = OTR_MESSAGES_CONTENT_URI_BY_ACCOUNT_AND_CONTACT.buildUpon();
ContentUris.appendId(builder, accountId);
builder.appendPath(username);
return builder.build();
}
/**
+ * Gets the Uri to query off the record messages by provider.
+ *
+ * @param providerId the service provider id.
+ * @return the Uri
+ */
+ public static final Uri getOtrMessagesContentUriByProvider(long providerId) {
+ Uri.Builder builder = OTR_MESSAGES_CONTENT_URI_BY_PROVIDER.buildUpon();
+ ContentUris.appendId(builder, providerId);
+ return builder.build();
+ }
+
+ /**
+ * Gets the Uri to query off the record messages by account.
+ *
+ * @param accountId the account id.
+ * @return the Uri
+ */
+ public static final Uri getOtrMessagesContentUriByAccount(long accountId) {
+ Uri.Builder builder = OTR_MESSAGES_CONTENT_URI_BY_ACCOUNT.buildUpon();
+ ContentUris.appendId(builder, accountId);
+ return builder.build();
+ }
+
+ /**
* The content:// style URL for this table
*/
public static final Uri CONTENT_URI =
- Uri.parse("content://im/messages");
+ Uri.parse("content://im/messages");
+
+ /**
+ * The content:// style URL for messages by thread id
+ */
+ public static final Uri CONTENT_URI_MESSAGES_BY_THREAD_ID =
+ Uri.parse("content://im/messagesByThreadId");
+
+ /**
+ * The content:// style URL for messages by account and contact
+ */
+ public static final Uri CONTENT_URI_MESSAGES_BY_ACCOUNT_AND_CONTACT =
+ Uri.parse("content://im/messagesByAcctAndContact");
+
+ /**
+ * The content:// style URL for messages by provider
+ */
+ public static final Uri CONTENT_URI_MESSAGES_BY_PROVIDER =
+ Uri.parse("content://im/messagesByProvider");
+
+ /**
+ * The content:// style URL for messages by account
+ */
+ public static final Uri CONTENT_URI_BY_ACCOUNT =
+ Uri.parse("content://im/messagesByAccount");
+
+ /**
+ * The content:// style url for off the record messages
+ */
+ public static final Uri OTR_MESSAGES_CONTENT_URI =
+ Uri.parse("content://im/otrMessages");
/**
- * The content:// style URL for messages by provider and account
+ * The content:// style url for off the record messages by thread id
*/
- public static final Uri CONTENT_URI_MESSAGES_BY =
- Uri.parse("content://im/messagesBy");
+ public static final Uri OTR_MESSAGES_CONTENT_URI_BY_THREAD_ID =
+ Uri.parse("content://im/otrMessagesByThreadId");
+
+ /**
+ * The content:// style url for off the record messages by account and contact
+ */
+ public static final Uri OTR_MESSAGES_CONTENT_URI_BY_ACCOUNT_AND_CONTACT =
+ Uri.parse("content://im/otrMessagesByAcctAndContact");
+
+ /**
+ * The content:// style URL for off the record messages by provider
+ */
+ public static final Uri OTR_MESSAGES_CONTENT_URI_BY_PROVIDER =
+ Uri.parse("content://im/otrMessagesByProvider");
+
+ /**
+ * The content:// style URL for off the record messages by account
+ */
+ public static final Uri OTR_MESSAGES_CONTENT_URI_BY_ACCOUNT =
+ Uri.parse("content://im/otrMessagesByAccount");
/**
* The MIME type of {@link #CONTENT_URI} providing a directory of
* people.
*/
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/im-messages";
+ public static final String CONTENT_TYPE =
+ "vnd.android.cursor.dir/im-messages";
/**
* The MIME type of a {@link #CONTENT_URI} subdirectory of a single
@@ -992,6 +1125,11 @@ public class Im {
*/
public static final String DEFAULT_SORT_ORDER = "date ASC";
+ /**
+ * The "contact" column. This is not a real column in the messages table, but a
+ * temoprary column created when querying for messages (joined with the contacts table)
+ */
+ public static final String CONTACT = "contact";
}
/**
@@ -1119,67 +1257,6 @@ public class Im {
}
/**
- * Columns from the GroupMessages table
- */
- public interface GroupMessageColumns extends BaseMessageColumns {
- /**
- * The group this message belongs to
- * <p>Type: TEXT</p>
- */
- String GROUP = "groupId";
- }
-
- /**
- * This table contains group messages.
- */
- public final static class GroupMessages implements BaseColumns,
- GroupMessageColumns {
- private GroupMessages() {}
-
- /**
- * Gets the Uri to query group messages by group.
- *
- * @param groupId the group id.
- * @return the Uri
- */
- public static final Uri getContentUriByGroup(long groupId) {
- Uri.Builder builder = CONTENT_URI_GROUP_MESSAGES_BY.buildUpon();
- ContentUris.appendId(builder, groupId);
- return builder.build();
- }
-
- /**
- * The content:// style URL for this table
- */
- public static final Uri CONTENT_URI =
- Uri.parse("content://im/groupMessages");
-
- /**
- * The content:// style URL for group messages by provider and account
- */
- public static final Uri CONTENT_URI_GROUP_MESSAGES_BY =
- Uri.parse("content://im/groupMessagesBy");
-
- /**
- * The MIME type of {@link #CONTENT_URI} providing a directory of
- * group messages.
- */
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/im-groupMessages";
-
- /**
- * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
- * group message.
- */
- public static final String CONTENT_ITEM_TYPE =
- "vnd.android.cursor.item/im-groupMessages";
-
- /**
- * The default sort order for this table
- */
- public static final String DEFAULT_SORT_ORDER = "date ASC";
- }
-
- /**
* Columns from the Avatars table
*/
public interface AvatarsColumns {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 42a5075..a7ba3a2 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1174,6 +1174,22 @@ public final class Settings {
public static final Uri DEFAULT_NOTIFICATION_URI = getUriFor(NOTIFICATION_SOUND);
/**
+ * Persistent store for the system-wide default alarm alert.
+ *
+ * @see #RINGTONE
+ * @see #DEFAULT_ALARM_ALERT_URI
+ */
+ public static final String ALARM_ALERT = "alarm_alert";
+
+ /**
+ * A {@link Uri} that will point to the current default alarm alert at
+ * any given time.
+ *
+ * @see #DEFAULT_ALARM_ALERT_URI
+ */
+ public static final Uri DEFAULT_ALARM_ALERT_URI = getUriFor(ALARM_ALERT);
+
+ /**
* Setting to enable Auto Replace (AutoText) in text editors. 1 = On, 0 = Off
*/
public static final String TEXT_AUTO_REPLACE = "auto_replace";
@@ -2582,6 +2598,32 @@ public final class Settings {
"gtalk_nosync_heartbeat_ping_interval_ms";
/**
+ * The maximum heartbeat interval used while on the WIFI network.
+ */
+ public static final String GTALK_SERVICE_WIFI_MAX_HEARTBEAT_INTERVAL_MS =
+ "gtalk_wifi_max_heartbeat_ping_interval_ms";
+
+ /**
+ * The minimum interval for how frequently we send heartbeat pings to the GTalk server.
+ */
+ public static final String GTALK_SERVICE_MIN_HEARTBEAT_INTERVAL_MS =
+ "gtalk_min_heartbeat_ping_interval_ms";
+
+ /**
+ * The scale down factor used by adaptive heartbeat logic (to scale down the heartbeat
+ * interval) when the previous interval fails to get a response from the server.
+ */
+ public static final String GTALK_SERVICE_ADAPTIVE_HEARTBEAT_SCALER =
+ "gtalk_adaptive_heartbeat_scaler";
+
+ /**
+ * The trigger for adaptively scaling down the heartbeat interval. This is the number of
+ * consecutive times we failed to get a server response for sending the heartbeat ping.
+ */
+ public static final String GTALK_SERVICE_ADAPTIVE_HEARTBEAT_TRIGGER =
+ "gtalk_adaptive_heartbeat_trigger";
+
+ /**
* How long we wait to receive a heartbeat ping acknowledgement (or another packet)
* from the GTalk server, before deeming the connection dead.
*/
diff --git a/core/java/android/provider/SocialContract.java b/core/java/android/provider/SocialContract.java
new file mode 100644
index 0000000..d4a9c48
--- /dev/null
+++ b/core/java/android/provider/SocialContract.java
@@ -0,0 +1,174 @@
+/*
+ * 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.provider;
+
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+
+/**
+ * The contract between the social provider and applications. Contains
+ * definitions for the supported URIs and columns.
+ *
+ * @hide
+ */
+public class SocialContract {
+ /** The authority for the social provider */
+ public static final String AUTHORITY = "com.android.social";
+
+ /** A content:// style uri to the authority for the contacts provider */
+ public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
+
+ private interface ActivitiesColumns {
+ /**
+ * The package name that owns this social activity.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String PACKAGE = "package";
+
+ /**
+ * The mime-type of this social activity.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String MIMETYPE = "mimetype";
+
+ /**
+ * Internal raw identifier for this social activity. This field is
+ * analogous to the <code>atom:id</code> element defined in RFC 4287.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String RAW_ID = "raw_id";
+
+ /**
+ * Reference to another {@link Activities#RAW_ID} that this social activity
+ * is replying to. This field is analogous to the
+ * <code>thr:in-reply-to</code> element defined in RFC 4685.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String IN_REPLY_TO = "in_reply_to";
+
+ /**
+ * Reference to the {@link android.provider.ContactsContract.Contacts#_ID} that authored
+ * this social activity. This field is analogous to the <code>atom:author</code>
+ * element defined in RFC 4287.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String AUTHOR_CONTACT_ID = "author_contact_id";
+
+ /**
+ * Optional reference to the {@link android.provider.ContactsContract.Contacts#_ID} this
+ * social activity is targeted towards. If more than one direct target, this field may
+ * be left undefined. This field is analogous to the
+ * <code>activity:target</code> element defined in the Atom Activity
+ * Extensions Internet-Draft.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String TARGET_CONTACT_ID = "target_contact_id";
+
+ /**
+ * Timestamp when this social activity was published, in a
+ * {@link System#currentTimeMillis()} time base. This field is analogous
+ * to the <code>atom:published</code> element defined in RFC 4287.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String PUBLISHED = "published";
+
+ /**
+ * Timestamp when the original social activity in a thread was
+ * published. For activities that have an in-reply-to field specified, the
+ * content provider will automatically populate this field with the
+ * timestamp of the original activity.
+ * <p>
+ * This field is useful for sorting order of activities that keeps together all
+ * messages in each thread.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String THREAD_PUBLISHED = "thread_published";
+
+ /**
+ * Title of this social activity. This field is analogous to the
+ * <code>atom:title</code> element defined in RFC 4287.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String TITLE = "title";
+
+ /**
+ * Summary of this social activity. This field is analogous to the
+ * <code>atom:summary</code> element defined in RFC 4287.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String SUMMARY = "summary";
+
+ /**
+ * A URI associated this social activity. This field is analogous to the
+ * <code>atom:link rel="alternate"</code> element defined in RFC 4287.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String LINK = "link";
+
+ /**
+ * Optional thumbnail specific to this social activity. This is the raw
+ * bytes of an image that could be inflated using {@link BitmapFactory}.
+ * <p>
+ * Type: BLOB
+ */
+ public static final String THUMBNAIL = "thumbnail";
+ }
+
+ public static final class Activities implements BaseColumns, ActivitiesColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Activities() {
+ }
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "activities");
+
+ /**
+ * The content:// style URI for this table filtered to the set of social activities
+ * authored by a specific {@link android.provider.ContactsContract.Contacts#_ID}.
+ */
+ public static final Uri CONTENT_AUTHORED_BY_URI =
+ Uri.withAppendedPath(CONTENT_URI, "authored_by");
+
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of social
+ * activities.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/activity";
+
+ /**
+ * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
+ * social activity.
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/activity";
+ }
+
+}
diff --git a/core/java/android/provider/SubscribedFeeds.java b/core/java/android/provider/SubscribedFeeds.java
index 4d430d5..f94b442 100644
--- a/core/java/android/provider/SubscribedFeeds.java
+++ b/core/java/android/provider/SubscribedFeeds.java
@@ -20,6 +20,7 @@ import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
+import android.accounts.Account;
/**
* The SubscribedFeeds provider stores all information about subscribed feeds.
@@ -99,7 +100,7 @@ public class SubscribedFeeds {
/**
* The default sort order for this table
*/
- public static final String DEFAULT_SORT_ORDER = "_SYNC_ACCOUNT ASC";
+ public static final String DEFAULT_SORT_ORDER = "_SYNC_ACCOUNT_TYPE, _SYNC_ACCOUNT ASC";
}
/**
@@ -114,38 +115,36 @@ public class SubscribedFeeds {
* @return the Uri of the feed that was added
*/
public static Uri addFeed(ContentResolver resolver,
- String feed, String account,
+ String feed, Account account,
String authority, String service) {
ContentValues values = new ContentValues();
values.put(SubscribedFeeds.Feeds.FEED, feed);
- values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT, account);
+ values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT, account.mName);
+ values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE, account.mType);
values.put(SubscribedFeeds.Feeds.AUTHORITY, authority);
values.put(SubscribedFeeds.Feeds.SERVICE, service);
return resolver.insert(SubscribedFeeds.Feeds.CONTENT_URI, values);
}
public static int deleteFeed(ContentResolver resolver,
- String feed, String account, String authority) {
+ String feed, Account account, String authority) {
StringBuilder where = new StringBuilder();
where.append(SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=?");
+ where.append(" AND " + SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "=?");
where.append(" AND " + SubscribedFeeds.Feeds.FEED + "=?");
where.append(" AND " + SubscribedFeeds.Feeds.AUTHORITY + "=?");
return resolver.delete(SubscribedFeeds.Feeds.CONTENT_URI,
- where.toString(), new String[] {account, feed, authority});
+ where.toString(), new String[] {account.mName, account.mType, feed, authority});
}
public static int deleteFeeds(ContentResolver resolver,
- String account, String authority) {
+ Account account, String authority) {
StringBuilder where = new StringBuilder();
where.append(SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=?");
+ where.append(" AND " + SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "=?");
where.append(" AND " + SubscribedFeeds.Feeds.AUTHORITY + "=?");
return resolver.delete(SubscribedFeeds.Feeds.CONTENT_URI,
- where.toString(), new String[] {account, authority});
- }
-
- public static String gtalkServiceRoutingInfoFromAccountAndResource(
- String account, String res) {
- return Uri.parse("gtalk://" + account + "/" + res).toString();
+ where.toString(), new String[] {account.mName, account.mType, authority});
}
/**
@@ -157,6 +156,12 @@ public class SubscribedFeeds {
* <P>Type: TEXT</P>
*/
public static final String _SYNC_ACCOUNT = SyncConstValue._SYNC_ACCOUNT;
+
+ /**
+ * The account type.
+ * <P>Type: TEXT</P>
+ */
+ public static final String _SYNC_ACCOUNT_TYPE = SyncConstValue._SYNC_ACCOUNT_TYPE;
}
/**
@@ -199,6 +204,6 @@ public class SubscribedFeeds {
/**
* The default sort order for this table
*/
- public static final String DEFAULT_SORT_ORDER = "_SYNC_ACCOUNT ASC";
+ public static final String DEFAULT_SORT_ORDER = "_SYNC_ACCOUNT_TYPE, _SYNC_ACCOUNT ASC";
}
}
diff --git a/core/java/android/provider/Sync.java b/core/java/android/provider/Sync.java
new file mode 100644
index 0000000..c9bde0e
--- /dev/null
+++ b/core/java/android/provider/Sync.java
@@ -0,0 +1,649 @@
+/*
+ * 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.
+ */
+
+package android.provider;
+
+import android.content.ContentQueryMap;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Handler;
+import android.accounts.Account;
+import android.text.TextUtils;
+
+import java.util.Map;
+
+/**
+ * The Sync provider stores information used in managing the syncing of the device,
+ * including the history and pending syncs.
+ *
+ * @hide
+ */
+public final class Sync {
+ // utility class
+ private Sync() {}
+
+ /**
+ * The content url for this provider.
+ */
+ public static final Uri CONTENT_URI = Uri.parse("content://sync");
+
+ /**
+ * Columns from the stats table.
+ */
+ public interface StatsColumns {
+ /**
+ * The sync account.
+ * <P>Type: TEXT</P>
+ */
+ public static final String ACCOUNT = "account";
+
+ /**
+ * The sync account type.
+ * <P>Type: TEXT</P>
+ */
+ public static final String ACCOUNT_TYPE = "account_type";
+
+ /**
+ * The content authority (contacts, calendar, etc.).
+ * <P>Type: TEXT</P>
+ */
+ public static final String AUTHORITY = "authority";
+ }
+
+ /**
+ * Provides constants and utility methods to access and use the stats table.
+ */
+ public static final class Stats implements BaseColumns, StatsColumns {
+
+ // utility class
+ private Stats() {}
+
+ /**
+ * The content url for this table.
+ */
+ public static final Uri CONTENT_URI =
+ Uri.parse("content://sync/stats");
+
+ /** Projection for the _id column in the stats table. */
+ public static final String[] SYNC_STATS_PROJECTION = {_ID};
+ }
+
+ /**
+ * Columns from the history table.
+ */
+ public interface HistoryColumns {
+ /**
+ * The ID of the stats row corresponding to this event.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String STATS_ID = "stats_id";
+
+ /**
+ * The source of the sync event (LOCAL, POLL, USER, SERVER).
+ * <P>Type: INTEGER</P>
+ */
+ public static final String SOURCE = "source";
+
+ /**
+ * The type of sync event (START, STOP).
+ * <P>Type: INTEGER</P>
+ */
+ public static final String EVENT = "event";
+
+ /**
+ * The time of the event.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String EVENT_TIME = "eventTime";
+
+ /**
+ * How long this event took. This is only valid if the EVENT is EVENT_STOP.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String ELAPSED_TIME = "elapsedTime";
+
+ /**
+ * Any additional message associated with this event.
+ * <P>Type: TEXT</P>
+ */
+ public static final String MESG = "mesg";
+
+ /**
+ * How much activity was performed sending data to the server. This is sync adapter
+ * specific, but usually is something like how many record update/insert/delete attempts
+ * were carried out. This is only valid if the EVENT is EVENT_STOP.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String UPSTREAM_ACTIVITY = "upstreamActivity";
+
+ /**
+ * How much activity was performed while receiving data from the server.
+ * This is sync adapter specific, but usually is something like how many
+ * records were received from the server. This is only valid if the
+ * EVENT is EVENT_STOP.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String DOWNSTREAM_ACTIVITY = "downstreamActivity";
+ }
+
+ /**
+ * Columns from the history table.
+ */
+ public interface StatusColumns {
+ /**
+ * How many syncs were completed for this account and authority.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String NUM_SYNCS = "numSyncs";
+
+ /**
+ * How long all the events for this account and authority took.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String TOTAL_ELAPSED_TIME = "totalElapsedTime";
+
+ /**
+ * The number of syncs with SOURCE_POLL.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String NUM_SOURCE_POLL = "numSourcePoll";
+
+ /**
+ * The number of syncs with SOURCE_SERVER.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String NUM_SOURCE_SERVER = "numSourceServer";
+
+ /**
+ * The number of syncs with SOURCE_LOCAL.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String NUM_SOURCE_LOCAL = "numSourceLocal";
+
+ /**
+ * The number of syncs with SOURCE_USER.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String NUM_SOURCE_USER = "numSourceUser";
+
+ /**
+ * The time in ms that the last successful sync ended. Will be null if
+ * there are no successful syncs. A successful sync is defined as one having
+ * MESG=MESG_SUCCESS.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String LAST_SUCCESS_TIME = "lastSuccessTime";
+
+ /**
+ * The SOURCE of the last successful sync. Will be null if
+ * there are no successful syncs. A successful sync is defined
+ * as one having MESG=MESG_SUCCESS.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String LAST_SUCCESS_SOURCE = "lastSuccessSource";
+
+ /**
+ * The end time in ms of the last sync that failed since the last successful sync.
+ * Will be null if there are no syncs or if the last one succeeded. A failed
+ * sync is defined as one where MESG isn't MESG_SUCCESS or MESG_CANCELED.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String LAST_FAILURE_TIME = "lastFailureTime";
+
+ /**
+ * The SOURCE of the last sync that failed since the last successful sync.
+ * Will be null if there are no syncs or if the last one succeeded. A failed
+ * sync is defined as one where MESG isn't MESG_SUCCESS or MESG_CANCELED.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String LAST_FAILURE_SOURCE = "lastFailureSource";
+
+ /**
+ * The MESG of the last sync that failed since the last successful sync.
+ * Will be null if there are no syncs or if the last one succeeded. A failed
+ * sync is defined as one where MESG isn't MESG_SUCCESS or MESG_CANCELED.
+ * <P>Type: STRING</P>
+ */
+ public static final String LAST_FAILURE_MESG = "lastFailureMesg";
+
+ /**
+ * Is set to 1 if a sync is pending, 0 if not.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String PENDING = "pending";
+ }
+
+ /**
+ * Provides constants and utility methods to access and use the history
+ * table.
+ */
+ public static class History implements BaseColumns,
+ StatsColumns,
+ HistoryColumns {
+
+ /**
+ * The content url for this table.
+ */
+ public static final Uri CONTENT_URI =
+ Uri.parse("content://sync/history");
+
+ /** Enum value for a sync start event. */
+ public static final int EVENT_START = 0;
+
+ /** Enum value for a sync stop event. */
+ public static final int EVENT_STOP = 1;
+
+ // TODO: i18n -- grab these out of resources.
+ /** String names for the sync event types. */
+ public static final String[] EVENTS = { "START", "STOP" };
+
+ /** Enum value for a server-initiated sync. */
+ public static final int SOURCE_SERVER = 0;
+
+ /** Enum value for a local-initiated sync. */
+ public static final int SOURCE_LOCAL = 1;
+ /**
+ * Enum value for a poll-based sync (e.g., upon connection to
+ * network)
+ */
+ public static final int SOURCE_POLL = 2;
+
+ /** Enum value for a user-initiated sync. */
+ public static final int SOURCE_USER = 3;
+
+ // TODO: i18n -- grab these out of resources.
+ /** String names for the sync source types. */
+ public static final String[] SOURCES = { "SERVER",
+ "LOCAL",
+ "POLL",
+ "USER" };
+
+ // Error types
+ public static final int ERROR_SYNC_ALREADY_IN_PROGRESS = 1;
+ public static final int ERROR_AUTHENTICATION = 2;
+ public static final int ERROR_IO = 3;
+ public static final int ERROR_PARSE = 4;
+ public static final int ERROR_CONFLICT = 5;
+ public static final int ERROR_TOO_MANY_DELETIONS = 6;
+ public static final int ERROR_TOO_MANY_RETRIES = 7;
+ public static final int ERROR_INTERNAL = 8;
+
+ // The MESG column will contain one of these or one of the Error types.
+ public static final String MESG_SUCCESS = "success";
+ public static final String MESG_CANCELED = "canceled";
+
+ private static final String FINISHED_SINCE_WHERE_CLAUSE = EVENT + "=" + EVENT_STOP
+ + " AND " + EVENT_TIME + ">? AND " + ACCOUNT + "=? AND " + ACCOUNT_TYPE + "=?"
+ + " AND " + AUTHORITY + "=?";
+
+ public static String mesgToString(String mesg) {
+ if (MESG_SUCCESS.equals(mesg)) return mesg;
+ if (MESG_CANCELED.equals(mesg)) return mesg;
+ switch (Integer.parseInt(mesg)) {
+ case ERROR_SYNC_ALREADY_IN_PROGRESS: return "already in progress";
+ case ERROR_AUTHENTICATION: return "bad authentication";
+ case ERROR_IO: return "network error";
+ case ERROR_PARSE: return "parse error";
+ case ERROR_CONFLICT: return "conflict detected";
+ case ERROR_TOO_MANY_DELETIONS: return "too many deletions";
+ case ERROR_TOO_MANY_RETRIES: return "too many retries";
+ case ERROR_INTERNAL: return "internal error";
+ default: return "unknown error";
+ }
+ }
+
+ // utility class
+ private History() {}
+
+ /**
+ * returns a cursor that queries the sync history in descending event time order
+ * @param contentResolver the ContentResolver to use for the query
+ * @return the cursor on the History table
+ */
+ public static Cursor query(ContentResolver contentResolver) {
+ return contentResolver.query(CONTENT_URI, null, null, null, EVENT_TIME + " desc");
+ }
+
+ public static boolean hasNewerSyncFinished(ContentResolver contentResolver,
+ Account account, String authority, long when) {
+ Cursor c = contentResolver.query(CONTENT_URI, new String[]{_ID},
+ FINISHED_SINCE_WHERE_CLAUSE,
+ new String[]{Long.toString(when), account.mName, account.mType, authority},
+ null);
+ try {
+ return c.getCount() > 0;
+ } finally {
+ c.close();
+ }
+ }
+ }
+
+ /**
+ * Provides constants and utility methods to access and use the authority history
+ * table, which contains information about syncs aggregated by account and authority.
+ * All the HistoryColumns except for EVENT are present, plus the AuthorityHistoryColumns.
+ */
+ public static class Status extends History implements StatusColumns {
+
+ /**
+ * The content url for this table.
+ */
+ public static final Uri CONTENT_URI = Uri.parse("content://sync/status");
+
+ // utility class
+ private Status() {}
+
+ /**
+ * returns a cursor that queries the authority sync history in descending event order of
+ * ACCOUNT, AUTHORITY
+ * @param contentResolver the ContentResolver to use for the query
+ * @return the cursor on the AuthorityHistory table
+ */
+ public static Cursor query(ContentResolver contentResolver) {
+ return contentResolver.query(CONTENT_URI, null, null, null,
+ ACCOUNT_TYPE + "," + ACCOUNT + "," + AUTHORITY);
+ }
+
+ public static class QueryMap extends ContentQueryMap {
+ public QueryMap(ContentResolver contentResolver,
+ boolean keepUpdated,
+ Handler handlerForUpdateNotifications) {
+ super(contentResolver.query(CONTENT_URI, null, null, null, null),
+ _ID, keepUpdated, handlerForUpdateNotifications);
+ }
+
+ public ContentValues get(Account account, String authority) {
+ Map<String, ContentValues> rows = getRows();
+ for (ContentValues values : rows.values()) {
+ if (values.getAsString(ACCOUNT).equals(account.mName)
+ && values.getAsString(ACCOUNT_TYPE).equals(account.mType)
+ && values.getAsString(AUTHORITY).equals(authority)) {
+ return values;
+ }
+ }
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Provides constants and utility methods to access and use the pending syncs table
+ */
+ public static final class Pending implements BaseColumns,
+ StatsColumns {
+
+ /**
+ * The content url for this table.
+ */
+ public static final Uri CONTENT_URI = Uri.parse("content://sync/pending");
+
+ // utility class
+ private Pending() {}
+
+ public static class QueryMap extends ContentQueryMap {
+ public QueryMap(ContentResolver contentResolver, boolean keepUpdated,
+ Handler handlerForUpdateNotifications) {
+ super(contentResolver.query(CONTENT_URI, null, null, null, null), _ID, keepUpdated,
+ handlerForUpdateNotifications);
+ }
+
+ public boolean isPending(Account account, String authority) {
+ Map<String, ContentValues> rows = getRows();
+ for (ContentValues values : rows.values()) {
+ if (values.getAsString(ACCOUNT).equals(account.mName)
+ && values.getAsString(ACCOUNT_TYPE).equals(account.mType)
+ && values.getAsString(AUTHORITY).equals(authority)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Columns from the history table.
+ */
+ public interface ActiveColumns {
+ /**
+ * The wallclock time of when the active sync started.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String START_TIME = "startTime";
+ }
+
+ /**
+ * Provides constants and utility methods to access and use the pending syncs table
+ */
+ public static final class Active implements BaseColumns,
+ StatsColumns,
+ ActiveColumns {
+
+ /**
+ * The content url for this table.
+ */
+ public static final Uri CONTENT_URI = Uri.parse("content://sync/active");
+
+ // utility class
+ private Active() {}
+
+ public static class QueryMap extends ContentQueryMap {
+ public QueryMap(ContentResolver contentResolver, boolean keepUpdated,
+ Handler handlerForUpdateNotifications) {
+ super(contentResolver.query(CONTENT_URI, null, null, null, null), _ID, keepUpdated,
+ handlerForUpdateNotifications);
+ }
+
+ public ContentValues getActiveSyncInfo() {
+ Map<String, ContentValues> rows = getRows();
+ for (ContentValues values : rows.values()) {
+ return values;
+ }
+ return null;
+ }
+
+ public Account getSyncingAccount() {
+ ContentValues values = getActiveSyncInfo();
+ if (values == null || TextUtils.isEmpty(values.getAsString(ACCOUNT))) {
+ return null;
+ }
+ return new Account(values.getAsString(ACCOUNT), values.getAsString(ACCOUNT_TYPE));
+ }
+
+ public String getSyncingAuthority() {
+ ContentValues values = getActiveSyncInfo();
+ return (values == null) ? null : values.getAsString(AUTHORITY);
+ }
+
+ public long getSyncStartTime() {
+ ContentValues values = getActiveSyncInfo();
+ return (values == null) ? -1 : values.getAsLong(START_TIME);
+ }
+ }
+ }
+
+ /**
+ * Columns in the settings table, which holds key/value pairs of settings.
+ */
+ public interface SettingsColumns {
+ /**
+ * The key of the setting
+ * <P>Type: TEXT</P>
+ */
+ public static final String KEY = "name";
+
+ /**
+ * The value of the settings
+ * <P>Type: TEXT</P>
+ */
+ public static final String VALUE = "value";
+ }
+
+ /**
+ * Provides constants and utility methods to access and use the settings
+ * table.
+ */
+ public static final class Settings implements BaseColumns, SettingsColumns {
+ /**
+ * The Uri of the settings table. This table behaves a little differently than
+ * normal tables. Updates are not allowed, only inserts, and inserts cause a replace
+ * to be performed, which first deletes the row if it is already present.
+ */
+ public static final Uri CONTENT_URI = Uri.parse("content://sync/settings");
+
+ /** controls whether or not the device listens for sync tickles */
+ public static final String SETTING_LISTEN_FOR_TICKLES = "listen_for_tickles";
+
+ /** controls whether or not the individual provider is synced when tickles are received */
+ public static final String SETTING_SYNC_PROVIDER_PREFIX = "sync_provider_";
+
+ /** query column project */
+ private static final String[] PROJECTION = { KEY, VALUE };
+
+ /**
+ * Convenience function for updating a single settings value as a
+ * boolean. This will either create a new entry in the table if the
+ * given name does not exist, or modify the value of the existing row
+ * with that name. Note that internally setting values are always
+ * stored as strings, so this function converts the given value to a
+ * string before storing it.
+ *
+ * @param contentResolver the ContentResolver to use to access the settings table
+ * @param name The name of the setting to modify.
+ * @param val The new value for the setting.
+ */
+ static private void putBoolean(ContentResolver contentResolver, String name, boolean val) {
+ ContentValues values = new ContentValues();
+ values.put(KEY, name);
+ values.put(VALUE, Boolean.toString(val));
+ // this insert is translated into an update by the underlying Sync provider
+ contentResolver.insert(CONTENT_URI, values);
+ }
+
+ /**
+ * Convenience function for getting a setting value as a boolean without using the
+ * QueryMap for light-weight setting querying.
+ * @param contentResolver The ContentResolver for querying the setting.
+ * @param name The name of the setting to query
+ * @param def The default value for the setting.
+ * @return The value of the setting.
+ */
+ static public boolean getBoolean(ContentResolver contentResolver,
+ String name, boolean def) {
+ Cursor cursor = contentResolver.query(
+ CONTENT_URI,
+ PROJECTION,
+ KEY + "=?",
+ new String[] { name },
+ null);
+ try {
+ if (cursor != null && cursor.moveToFirst()) {
+ return Boolean.parseBoolean(cursor.getString(1));
+ }
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ return def;
+ }
+
+ /**
+ * A convenience method to set whether or not the provider is synced when
+ * it receives a network tickle.
+ *
+ * @param contentResolver the ContentResolver to use to access the settings table
+ * @param providerName the provider whose behavior is being controlled
+ * @param sync true if the provider should be synced when tickles are received for it
+ */
+ static public void setSyncProviderAutomatically(ContentResolver contentResolver,
+ String providerName, boolean sync) {
+ putBoolean(contentResolver, SETTING_SYNC_PROVIDER_PREFIX + providerName, sync);
+ }
+
+ /**
+ * A convenience method to set whether or not the device should listen to tickles.
+ *
+ * @param contentResolver the ContentResolver to use to access the settings table
+ * @param flag true if it should listen.
+ */
+ static public void setListenForNetworkTickles(ContentResolver contentResolver,
+ boolean flag) {
+ putBoolean(contentResolver, SETTING_LISTEN_FOR_TICKLES, flag);
+ }
+
+ public static class QueryMap extends ContentQueryMap {
+ private ContentResolver mContentResolver;
+
+ public QueryMap(ContentResolver contentResolver, boolean keepUpdated,
+ Handler handlerForUpdateNotifications) {
+ super(contentResolver.query(CONTENT_URI, null, null, null, null), KEY, keepUpdated,
+ handlerForUpdateNotifications);
+ mContentResolver = contentResolver;
+ }
+
+ /**
+ * Check if the provider should be synced when a network tickle is received
+ * @param providerName the provider whose setting we are querying
+ * @return true of the provider should be synced when a network tickle is received
+ */
+ public boolean getSyncProviderAutomatically(String providerName) {
+ return getBoolean(SETTING_SYNC_PROVIDER_PREFIX + providerName, true);
+ }
+
+ /**
+ * Set whether or not the provider is synced when it receives a network tickle.
+ *
+ * @param providerName the provider whose behavior is being controlled
+ * @param sync true if the provider should be synced when tickles are received for it
+ */
+ public void setSyncProviderAutomatically(String providerName, boolean sync) {
+ Settings.setSyncProviderAutomatically(mContentResolver, providerName, sync);
+ }
+
+ /**
+ * Set whether or not the device should listen for tickles.
+ *
+ * @param flag true if it should listen.
+ */
+ public void setListenForNetworkTickles(boolean flag) {
+ Settings.setListenForNetworkTickles(mContentResolver, flag);
+ }
+
+ /**
+ * Check if the device should listen to tickles.
+
+ * @return true if it should
+ */
+ public boolean getListenForNetworkTickles() {
+ return getBoolean(SETTING_LISTEN_FOR_TICKLES, true);
+ }
+
+ /**
+ * Convenience function for retrieving a single settings value
+ * as a boolean.
+ *
+ * @param name The name of the setting to retrieve.
+ * @param def Value to return if the setting is not defined.
+ * @return The setting's current value, or 'def' if it is not defined.
+ */
+ private boolean getBoolean(String name, boolean def) {
+ ContentValues values = getValues(name);
+ return values != null ? values.getAsBoolean(VALUE) : def;
+ }
+ }
+ }
+}
diff --git a/core/java/android/provider/SyncConstValue.java b/core/java/android/provider/SyncConstValue.java
index 6eb4398..30966eb 100644
--- a/core/java/android/provider/SyncConstValue.java
+++ b/core/java/android/provider/SyncConstValue.java
@@ -29,6 +29,12 @@ public interface SyncConstValue
public static final String _SYNC_ACCOUNT = "_sync_account";
/**
+ * The type of the account that was used to sync the entry to the device.
+ * <P>Type: TEXT</P>
+ */
+ public static final String _SYNC_ACCOUNT_TYPE = "_sync_account_type";
+
+ /**
* The unique ID for a row assigned by the sync source. NULL if the row has never been synced.
* <P>Type: TEXT</P>
*/
@@ -68,4 +74,9 @@ public interface SyncConstValue
* Used to indicate that this account is not synced
*/
public static final String NON_SYNCABLE_ACCOUNT = "non_syncable";
+
+ /**
+ * Used to indicate that this account is not synced
+ */
+ public static final String NON_SYNCABLE_ACCOUNT_TYPE = "android.local";
}
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 4078fa6..a2c253a 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -146,7 +146,13 @@ public final class Telephony {
* <P>Type: TEXT</P>
*/
public static final String SERVICE_CENTER = "service_center";
- }
+
+ /**
+ * Has the message been locked?
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String LOCKED = "locked";
+}
/**
* Contains all text based SMS messages.
@@ -1008,6 +1014,12 @@ public final class Telephony {
* <P>Type: INTEGER</P>
*/
public static final String THREAD_ID = "thread_id";
+
+ /**
+ * Has the message been locked?
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String LOCKED = "locked";
}
/**
diff --git a/core/java/android/syncml/pim/vcard/ContactStruct.java b/core/java/android/syncml/pim/vcard/ContactStruct.java
index afeb5cd..5a29112 100644
--- a/core/java/android/syncml/pim/vcard/ContactStruct.java
+++ b/core/java/android/syncml/pim/vcard/ContactStruct.java
@@ -17,6 +17,7 @@
package android.syncml.pim.vcard;
import android.content.AbstractSyncableContentProvider;
+import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -762,17 +763,16 @@ public class ContactStruct {
personId = ContentUris.parseId(personUri);
}
} else {
- personUri = provider.nonTransactionalInsert(People.CONTENT_URI, contentValues);
+ personUri = provider.insert(People.CONTENT_URI, contentValues);
if (personUri != null) {
personId = ContentUris.parseId(personUri);
ContentValues values = new ContentValues();
values.put(GroupMembership.PERSON_ID, personId);
values.put(GroupMembership.GROUP_ID, myContactsGroupId);
- Uri resultUri = provider.nonTransactionalInsert(
- GroupMembership.CONTENT_URI, values);
+ Uri resultUri = provider.insert(GroupMembership.CONTENT_URI, values);
if (resultUri == null) {
Log.e(LOG_TAG, "Faild to insert the person to MyContact.");
- provider.nonTransactionalDelete(personUri, null, null);
+ provider.delete(personUri, null, null);
personUri = null;
}
}
@@ -812,7 +812,7 @@ public class ContactStruct {
if (resolver != null) {
phoneUri = resolver.insert(Phones.CONTENT_URI, values);
} else {
- phoneUri = provider.nonTransactionalInsert(Phones.CONTENT_URI, values);
+ phoneUri = provider.insert(Phones.CONTENT_URI, values);
}
if (phoneData.isPrimary) {
primaryPhoneId = Long.parseLong(phoneUri.getLastPathSegment());
@@ -838,8 +838,7 @@ public class ContactStruct {
if (resolver != null) {
organizationUri = resolver.insert(Organizations.CONTENT_URI, values);
} else {
- organizationUri = provider.nonTransactionalInsert(
- Organizations.CONTENT_URI, values);
+ organizationUri = provider.insert(Organizations.CONTENT_URI, values);
}
if (organizationData.isPrimary) {
primaryOrganizationId = Long.parseLong(organizationUri.getLastPathSegment());
@@ -865,8 +864,7 @@ public class ContactStruct {
if (resolver != null) {
emailUri = resolver.insert(ContactMethods.CONTENT_URI, values);
} else {
- emailUri = provider.nonTransactionalInsert(
- ContactMethods.CONTENT_URI, values);
+ emailUri = provider.insert(ContactMethods.CONTENT_URI, values);
}
if (contactMethod.isPrimary) {
primaryEmailId = Long.parseLong(emailUri.getLastPathSegment());
@@ -875,8 +873,7 @@ public class ContactStruct {
if (resolver != null) {
resolver.insert(ContactMethods.CONTENT_URI, values);
} else {
- provider.nonTransactionalInsert(
- ContactMethods.CONTENT_URI, values);
+ provider.insert(ContactMethods.CONTENT_URI, values);
}
}
}
@@ -900,7 +897,7 @@ public class ContactStruct {
if (resolver != null) {
contentValuesArray.add(values);
} else {
- provider.nonTransactionalInsert(Extensions.CONTENT_URI, values);
+ provider.insert(Extensions.CONTENT_URI, values);
}
}
}
@@ -924,7 +921,7 @@ public class ContactStruct {
if (resolver != null) {
resolver.update(personUri, values, null, null);
} else {
- provider.nonTransactionalUpdate(personUri, values, null, null);
+ provider.update(personUri, values, null, null);
}
}
}
@@ -942,12 +939,12 @@ public class ContactStruct {
public void pushIntoAbstractSyncableContentProvider(
AbstractSyncableContentProvider provider, long myContactsGroupId) {
boolean successful = false;
- provider.beginTransaction();
+ provider.beginBatch();
try {
pushIntoContentProviderOrResolver(provider, myContactsGroupId);
successful = true;
} finally {
- provider.endTransaction(successful);
+ provider.endBatch(successful);
}
}
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 86261c4..f1bf0f4 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -19,7 +19,6 @@ package android.view;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
-import android.util.Config;
/**
* Object used to report movement (mouse, pen, finger, trackball) events. This
@@ -87,6 +86,7 @@ public final class MotionEvent implements Parcelable {
private long mDownTime;
private long mEventTime;
+ private long mEventTimeNano;
private int mAction;
private float mX;
private float mY;
@@ -123,6 +123,62 @@ public final class MotionEvent implements Parcelable {
return ev;
}
}
+
+ /**
+ * Create a new MotionEvent, filling in all of the basic values that
+ * define the motion.
+ *
+ * @param downTime The time (in ms) when the user originally pressed down to start
+ * a stream of position events. This must be obtained from {@link SystemClock#uptimeMillis()}.
+ * @param eventTime The the time (in ms) when this specific event was generated. This
+ * must be obtained from {@link SystemClock#uptimeMillis()}.
+ * @param eventTimeNano The the time (in ns) when this specific event was generated. This
+ * must be obtained from {@link System#nanoTime()}.
+ * @param action The kind of action being performed -- one of either
+ * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or
+ * {@link #ACTION_CANCEL}.
+ * @param x The X coordinate of this event.
+ * @param y The Y coordinate of this event.
+ * @param pressure The current pressure of this event. The pressure generally
+ * ranges from 0 (no pressure at all) to 1 (normal pressure), however
+ * values higher than 1 may be generated depending on the calibration of
+ * the input device.
+ * @param size A scaled value of the approximate size of the area being pressed when
+ * touched with the finger. The actual value in pixels corresponding to the finger
+ * touch is normalized with a device specific range of values
+ * and scaled to a value between 0 and 1.
+ * @param metaState The state of any meta / modifier keys that were in effect when
+ * the event was generated.
+ * @param xPrecision The precision of the X coordinate being reported.
+ * @param yPrecision The precision of the Y coordinate being reported.
+ * @param deviceId The id for the device that this event came from. An id of
+ * zero indicates that the event didn't come from a physical device; other
+ * numbers are arbitrary and you shouldn't depend on the values.
+ * @param edgeFlags A bitfield indicating which edges, if any, where touched by this
+ * MotionEvent.
+ *
+ * @hide
+ */
+ static public MotionEvent obtainNano(long downTime, long eventTime, long eventTimeNano,
+ int action, float x, float y, float pressure, float size, int metaState,
+ float xPrecision, float yPrecision, int deviceId, int edgeFlags) {
+ MotionEvent ev = obtain();
+ ev.mDeviceId = deviceId;
+ ev.mEdgeFlags = edgeFlags;
+ ev.mDownTime = downTime;
+ ev.mEventTime = eventTime;
+ ev.mEventTimeNano = eventTimeNano;
+ ev.mAction = action;
+ ev.mX = ev.mRawX = x;
+ ev.mY = ev.mRawY = y;
+ ev.mPressure = pressure;
+ ev.mSize = size;
+ ev.mMetaState = metaState;
+ ev.mXPrecision = xPrecision;
+ ev.mYPrecision = yPrecision;
+
+ return ev;
+ }
/**
* Create a new MotionEvent, filling in all of the basic values that
@@ -163,6 +219,7 @@ public final class MotionEvent implements Parcelable {
ev.mEdgeFlags = edgeFlags;
ev.mDownTime = downTime;
ev.mEventTime = eventTime;
+ ev.mEventTimeNano = eventTime * 1000000;
ev.mAction = action;
ev.mX = ev.mRawX = x;
ev.mY = ev.mRawY = y;
@@ -199,6 +256,7 @@ public final class MotionEvent implements Parcelable {
ev.mEdgeFlags = 0;
ev.mDownTime = downTime;
ev.mEventTime = eventTime;
+ ev.mEventTimeNano = eventTime * 1000000;
ev.mAction = action;
ev.mX = ev.mRawX = x;
ev.mY = ev.mRawY = y;
@@ -246,6 +304,7 @@ public final class MotionEvent implements Parcelable {
ev.mEdgeFlags = o.mEdgeFlags;
ev.mDownTime = o.mDownTime;
ev.mEventTime = o.mEventTime;
+ ev.mEventTimeNano = o.mEventTimeNano;
ev.mAction = o.mAction;
ev.mX = o.mX;
ev.mRawX = o.mRawX;
@@ -317,6 +376,16 @@ public final class MotionEvent implements Parcelable {
}
/**
+ * Returns the time (in ns) when this specific event was generated.
+ * The value is in nanosecond precision but it may not have nanosecond accuracy.
+ *
+ * @hide
+ */
+ public final long getEventTimeNano() {
+ return mEventTimeNano;
+ }
+
+ /**
* Returns the X coordinate of this event. Whole numbers are pixels; the
* value may have a fraction for input devices that are sub-pixel precise.
*/
@@ -644,6 +713,7 @@ public final class MotionEvent implements Parcelable {
public void writeToParcel(Parcel out, int flags) {
out.writeLong(mDownTime);
out.writeLong(mEventTime);
+ out.writeLong(mEventTimeNano);
out.writeInt(mAction);
out.writeFloat(mX);
out.writeFloat(mY);
@@ -675,6 +745,7 @@ public final class MotionEvent implements Parcelable {
private void readFromParcel(Parcel in) {
mDownTime = in.readLong();
mEventTime = in.readLong();
+ mEventTimeNano = in.readLong();
mAction = in.readInt();
mX = in.readFloat();
mY = in.readFloat();
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 082cca2..6519852 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -31,8 +31,9 @@ import android.os.ParcelFileDescriptor;
import android.util.AttributeSet;
import android.util.Config;
import android.util.Log;
-import java.util.ArrayList;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
import java.util.concurrent.locks.ReentrantLock;
import java.lang.ref.WeakReference;
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index d8bab56..e15a61c 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -79,6 +79,9 @@ public final class ViewRoot extends Handler implements ViewParent,
private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
private static final boolean WATCH_POINTER = false;
+ private static final boolean MEASURE_LATENCY = false;
+ private static LatencyTimer lt;
+
/**
* Maximum time we allow the user to roll the trackball enough to generate
* a key event, before resetting the counters.
@@ -193,6 +196,10 @@ public final class ViewRoot extends Handler implements ViewParent,
public ViewRoot(Context context) {
super();
+ if (MEASURE_LATENCY && lt == null) {
+ lt = new LatencyTimer(100, 1000);
+ }
+
++sInstanceCount;
// Initialize the statics when this class is first instantiated. This is
@@ -1585,7 +1592,17 @@ public final class ViewRoot extends Handler implements ViewParent,
boolean didFinish;
if (event == null) {
try {
+ long timeBeforeGettingEvents;
+ if (MEASURE_LATENCY) {
+ timeBeforeGettingEvents = System.nanoTime();
+ }
+
event = sWindowSession.getPendingPointerMove(mWindow);
+
+ if (MEASURE_LATENCY && event != null) {
+ lt.sample("9 Client got events ", System.nanoTime() - event.getEventTimeNano());
+ lt.sample("8 Client getting events ", timeBeforeGettingEvents - event.getEventTimeNano());
+ }
} catch (RemoteException e) {
}
didFinish = true;
@@ -1609,7 +1626,13 @@ public final class ViewRoot extends Handler implements ViewParent,
captureMotionLog("captureDispatchPointer", event);
}
event.offsetLocation(0, mCurScrollY);
+ if (MEASURE_LATENCY) {
+ lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano());
+ }
handled = mView.dispatchTouchEvent(event);
+ if (MEASURE_LATENCY) {
+ lt.sample("B Dispatched TouchEvents ", System.nanoTime() - event.getEventTimeNano());
+ }
if (!handled && isDown) {
int edgeSlop = mViewConfiguration.getScaledEdgeSlop();
@@ -2729,7 +2752,11 @@ public final class ViewRoot extends Handler implements ViewParent,
public void dispatchPointer(MotionEvent event, long eventTime) {
final ViewRoot viewRoot = mViewRoot.get();
- if (viewRoot != null) {
+ if (viewRoot != null) {
+ if (MEASURE_LATENCY) {
+ // Note: eventTime is in milliseconds
+ ViewRoot.lt.sample("* ViewRoot b4 dispatchPtr", System.nanoTime() - eventTime * 1000000);
+ }
viewRoot.dispatchPointer(event, eventTime);
} else {
new EventCompletion(mMainLooper, this, null, true, event);
diff --git a/core/java/android/view/ViewStub.java b/core/java/android/view/ViewStub.java
index e159de4..703a38f 100644
--- a/core/java/android/view/ViewStub.java
+++ b/core/java/android/view/ViewStub.java
@@ -23,6 +23,8 @@ import android.util.AttributeSet;
import com.android.internal.R;
+import java.lang.ref.WeakReference;
+
/**
* A ViewStub is an invisible, zero-sized View that can be used to lazily inflate
* layout resources at runtime.
@@ -68,6 +70,8 @@ public final class ViewStub extends View {
private int mLayoutResource = 0;
private int mInflatedId;
+ private WeakReference<View> mInflatedViewRef;
+
private OnInflateListener mInflateListener;
public ViewStub(Context context) {
@@ -196,9 +200,15 @@ public final class ViewStub extends View {
*/
@Override
public void setVisibility(int visibility) {
- super.setVisibility(visibility);
-
- if (visibility == VISIBLE || visibility == INVISIBLE) {
+ if (mInflatedViewRef != null) {
+ View view = mInflatedViewRef.get();
+ if (view != null) {
+ view.setVisibility(visibility);
+ } else {
+ throw new IllegalStateException("setVisibility called on un-referenced view");
+ }
+ } else if (visibility == VISIBLE || visibility == INVISIBLE) {
+ super.setVisibility(visibility);
inflate();
}
}
@@ -234,6 +244,8 @@ public final class ViewStub extends View {
parent.addView(view, index);
}
+ mInflatedViewRef = new WeakReference(view);
+
if (mInflateListener != null) {
mInflateListener.onInflate(this, view);
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index d7457a0..2c32d8b 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -56,11 +56,11 @@ public abstract class Window {
public static final int FEATURE_CONTEXT_MENU = 6;
/** Flag for custom title. You cannot combine this feature with other title features. */
public static final int FEATURE_CUSTOM_TITLE = 7;
- /* Flag for asking for an OpenGL enabled window.
+ /** Flag for asking for an OpenGL enabled window.
All 2D graphics will be handled by OpenGL ES.
- Private for now, until it is better tested (not shipping in 1.0)
+ @hide
*/
- private static final int FEATURE_OPENGL = 8;
+ public static final int FEATURE_OPENGL = 8;
/** Flag for setting the progress bar's visibility to VISIBLE */
public static final int PROGRESS_VISIBILITY_ON = -1;
/** Flag for setting the progress bar's visibility to GONE */
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index ba3f78c..e04ae72 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -109,6 +109,8 @@ class BrowserFrame extends Handler {
CacheManager.init(context);
// create CookieSyncManager with current Context
CookieSyncManager.createInstance(context);
+ // create PluginManager with current Context
+ PluginManager.getInstance(context);
}
AssetManager am = context.getAssets();
nativeCreateFrame(w, am, proxy.getBackForwardList());
@@ -119,7 +121,7 @@ class BrowserFrame extends Handler {
mDatabase = WebViewDatabase.getInstance(context);
mWebViewCore = w;
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.BROWSER_FRAME) {
Log.v(LOGTAG, "BrowserFrame constructor: this=" + this);
}
}
@@ -143,6 +145,17 @@ class BrowserFrame extends Handler {
}
/**
+ * Load a url with "POST" method from the network into the main frame.
+ * @param url The url to load.
+ * @param data The data for POST request.
+ */
+ public void postUrl(String url, byte[] data) {
+ mLoadInitFromJava = true;
+ nativePostUrl(url, data);
+ mLoadInitFromJava = false;
+ }
+
+ /**
* Load the content as if it was loaded by the provided base URL. The
* failUrl is used as the history entry for the load data. If null or
* an empty string is passed for the failUrl, then no history entry is
@@ -330,7 +343,7 @@ class BrowserFrame extends Handler {
switch (msg.what) {
case FRAME_COMPLETED: {
if (mSettings.getSavePassword() && hasPasswordField()) {
- if (WebView.DEBUG) {
+ if (DebugFlags.BROWSER_FRAME) {
Assert.assertNotNull(mCallbackProxy.getBackForwardList()
.getCurrentItem());
}
@@ -479,7 +492,7 @@ class BrowserFrame extends Handler {
}
if (mSettings.getSavePassword() && hasPasswordField()) {
try {
- if (WebView.DEBUG) {
+ if (DebugFlags.BROWSER_FRAME) {
Assert.assertNotNull(mCallbackProxy.getBackForwardList()
.getCurrentItem());
}
@@ -527,7 +540,7 @@ class BrowserFrame extends Handler {
// is this resource the main-frame top-level page?
boolean isMainFramePage = mIsMainFrame;
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.BROWSER_FRAME) {
Log.v(LOGTAG, "startLoadingResource: url=" + url + ", method="
+ method + ", postData=" + postData + ", isHighPriority="
+ isHighPriority + ", isMainFramePage=" + isMainFramePage);
@@ -752,6 +765,8 @@ class BrowserFrame extends Handler {
*/
private native void nativeLoadUrl(String url);
+ private native void nativePostUrl(String url, byte[] postData);
+
private native void nativeLoadData(String baseUrl, String data,
String mimeType, String encoding, String failUrl);
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index 7897435..4d471f7 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -51,7 +51,6 @@ public final class CacheManager {
private static final String NO_STORE = "no-store";
private static final String NO_CACHE = "no-cache";
- private static final String PRIVATE = "private";
private static final String MAX_AGE = "max-age";
private static long CACHE_THRESHOLD = 6 * 1024 * 1024;
@@ -321,7 +320,7 @@ public final class CacheManager {
}
}
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.CACHE_MANAGER) {
Log.v(LOGTAG, "getCacheFile for url " + url);
}
@@ -340,7 +339,7 @@ public final class CacheManager {
* @hide - hide createCacheFile since it has a parameter of type headers, which is
* in a hidden package.
*/
- // can be called from any thread
+ // only called from WebCore thread
public static CacheResult createCacheFile(String url, int statusCode,
Headers headers, String mimeType, boolean forceCache) {
if (!forceCache && mDisabled) {
@@ -349,17 +348,25 @@ public final class CacheManager {
// according to the rfc 2616, the 303 response MUST NOT be cached.
if (statusCode == 303) {
+ // remove the saved cache if there is any
+ mDataBase.removeCache(url);
return null;
}
// like the other browsers, do not cache redirects containing a cookie
// header.
if (checkCacheRedirect(statusCode) && !headers.getSetCookie().isEmpty()) {
+ // remove the saved cache if there is any
+ mDataBase.removeCache(url);
return null;
}
CacheResult ret = parseHeaders(statusCode, headers, mimeType);
- if (ret != null) {
+ if (ret == null) {
+ // this should only happen if the headers has "no-store" in the
+ // cache-control. remove the saved cache if there is any
+ mDataBase.removeCache(url);
+ } else {
setupFiles(url, ret);
try {
ret.outStream = new FileOutputStream(ret.outFile);
@@ -415,7 +422,7 @@ public final class CacheManager {
mDataBase.addCache(url, cacheRet);
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.CACHE_MANAGER) {
Log.v(LOGTAG, "saveCacheFile for url " + url);
}
}
@@ -628,7 +635,7 @@ public final class CacheManager {
// must be re-validated on every load. It does not mean that
// the content can not be cached. set to expire 0 means it
// can only be used in CACHE_MODE_CACHE_ONLY case
- if (NO_CACHE.equals(controls[i]) || PRIVATE.equals(controls[i])) {
+ if (NO_CACHE.equals(controls[i])) {
ret.expires = 0;
} else if (controls[i].startsWith(MAX_AGE)) {
int separator = controls[i].indexOf('=');
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 17d3f94..c407044 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -72,36 +72,38 @@ class CallbackProxy extends Handler {
private final Context mContext;
// Message Ids
- private static final int PAGE_STARTED = 100;
- private static final int RECEIVED_ICON = 101;
- private static final int RECEIVED_TITLE = 102;
- private static final int OVERRIDE_URL = 103;
- private static final int AUTH_REQUEST = 104;
- private static final int SSL_ERROR = 105;
- private static final int PROGRESS = 106;
- private static final int UPDATE_VISITED = 107;
- private static final int LOAD_RESOURCE = 108;
- private static final int CREATE_WINDOW = 109;
- private static final int CLOSE_WINDOW = 110;
- private static final int SAVE_PASSWORD = 111;
- private static final int JS_ALERT = 112;
- private static final int JS_CONFIRM = 113;
- private static final int JS_PROMPT = 114;
- private static final int JS_UNLOAD = 115;
- private static final int ASYNC_KEYEVENTS = 116;
- private static final int TOO_MANY_REDIRECTS = 117;
- private static final int DOWNLOAD_FILE = 118;
- private static final int REPORT_ERROR = 119;
- private static final int RESEND_POST_DATA = 120;
- private static final int PAGE_FINISHED = 121;
- private static final int REQUEST_FOCUS = 122;
- private static final int SCALE_CHANGED = 123;
- private static final int RECEIVED_CERTIFICATE = 124;
- private static final int SWITCH_OUT_HISTORY = 125;
- private static final int JS_TIMEOUT = 126;
+ private static final int PAGE_STARTED = 100;
+ private static final int RECEIVED_ICON = 101;
+ private static final int RECEIVED_TITLE = 102;
+ private static final int OVERRIDE_URL = 103;
+ private static final int AUTH_REQUEST = 104;
+ private static final int SSL_ERROR = 105;
+ private static final int PROGRESS = 106;
+ private static final int UPDATE_VISITED = 107;
+ private static final int LOAD_RESOURCE = 108;
+ private static final int CREATE_WINDOW = 109;
+ private static final int CLOSE_WINDOW = 110;
+ private static final int SAVE_PASSWORD = 111;
+ private static final int JS_ALERT = 112;
+ private static final int JS_CONFIRM = 113;
+ private static final int JS_PROMPT = 114;
+ private static final int JS_UNLOAD = 115;
+ private static final int ASYNC_KEYEVENTS = 116;
+ private static final int TOO_MANY_REDIRECTS = 117;
+ private static final int DOWNLOAD_FILE = 118;
+ private static final int REPORT_ERROR = 119;
+ private static final int RESEND_POST_DATA = 120;
+ private static final int PAGE_FINISHED = 121;
+ private static final int REQUEST_FOCUS = 122;
+ private static final int SCALE_CHANGED = 123;
+ private static final int RECEIVED_CERTIFICATE = 124;
+ private static final int SWITCH_OUT_HISTORY = 125;
+ private static final int EXCEEDED_DATABASE_QUOTA = 126;
+ private static final int JS_TIMEOUT = 127;
+ private static final int ADD_MESSAGE_TO_CONSOLE = 128;
// Message triggered by the client to resume execution
- private static final int NOTIFY = 200;
+ private static final int NOTIFY = 200;
// Result transportation object for returning results across thread
// boundaries.
@@ -389,6 +391,23 @@ class CallbackProxy extends Handler {
}
break;
+ case EXCEEDED_DATABASE_QUOTA:
+ if (mWebChromeClient != null) {
+ HashMap<String, Object> map =
+ (HashMap<String, Object>) msg.obj;
+ String databaseIdentifier =
+ (String) map.get("databaseIdentifier");
+ String url = (String) map.get("url");
+ long currentQuota =
+ ((Long) map.get("currentQuota")).longValue();
+ WebStorage.QuotaUpdater quotaUpdater =
+ (WebStorage.QuotaUpdater) map.get("quotaUpdater");
+
+ mWebChromeClient.onExceededDatabaseQuota(url,
+ databaseIdentifier, currentQuota, quotaUpdater);
+ }
+ break;
+
case JS_ALERT:
if (mWebChromeClient != null) {
final JsResult res = (JsResult) msg.obj;
@@ -563,6 +582,13 @@ class CallbackProxy extends Handler {
case SWITCH_OUT_HISTORY:
mWebView.switchOutDrawHistory();
break;
+
+ case ADD_MESSAGE_TO_CONSOLE:
+ String message = msg.getData().getString("message");
+ String sourceID = msg.getData().getString("sourceID");
+ int lineNumber = msg.getData().getInt("lineNumber");
+ mWebChromeClient.addMessageToConsole(message, lineNumber, sourceID);
+ break;
}
}
@@ -834,7 +860,7 @@ class CallbackProxy extends Handler {
String password, Message resumeMsg) {
// resumeMsg should be null at this point because we want to create it
// within the CallbackProxy.
- if (WebView.DEBUG) {
+ if (DebugFlags.CALLBACK_PROXY) {
junit.framework.Assert.assertNull(resumeMsg);
}
resumeMsg = obtainMessage(NOTIFY);
@@ -1037,6 +1063,60 @@ class CallbackProxy extends Handler {
}
/**
+ * Called by WebViewCore to inform the Java side that the current origin
+ * has overflowed it's database quota. Called in the WebCore thread so
+ * posts a message to the UI thread that will prompt the WebChromeClient
+ * for what to do. On return back to C++ side, the WebCore thread will
+ * sleep pending a new quota value.
+ * @param url The URL that caused the quota overflow.
+ * @param databaseIdentifier The identifier of the database that the
+ * transaction that caused the overflow was running on.
+ * @param currentQuota The current quota the origin is allowed.
+ * @param quotaUpdater An instance of a class encapsulating a callback
+ * to WebViewCore to run when the decision to allow or deny more
+ * quota has been made.
+ */
+ public void onExceededDatabaseQuota(
+ String url, String databaseIdentifier, long currentQuota,
+ WebStorage.QuotaUpdater quotaUpdater) {
+ if (mWebChromeClient == null) {
+ quotaUpdater.updateQuota(currentQuota);
+ return;
+ }
+
+ Message exceededQuota = obtainMessage(EXCEEDED_DATABASE_QUOTA);
+ HashMap<String, Object> map = new HashMap();
+ map.put("databaseIdentifier", databaseIdentifier);
+ map.put("url", url);
+ map.put("currentQuota", currentQuota);
+ map.put("quotaUpdater", quotaUpdater);
+ exceededQuota.obj = map;
+ sendMessage(exceededQuota);
+ }
+
+ /**
+ * Called by WebViewCore when we have a message to be added to the JavaScript
+ * error console. Sends a message to the Java side with the details.
+ * @param message The message to add to the console.
+ * @param lineNumber The lineNumber of the source file on which the error
+ * occurred.
+ * @param sourceID The filename of the source file in which the error
+ * occurred.
+ * @hide pending API counsel.
+ */
+ public void addMessageToConsole(String message, int lineNumber, String sourceID) {
+ if (mWebChromeClient == null) {
+ return;
+ }
+
+ Message msg = obtainMessage(ADD_MESSAGE_TO_CONSOLE);
+ msg.getData().putString("message", message);
+ msg.getData().putString("sourceID", sourceID);
+ msg.getData().putInt("lineNumber", lineNumber);
+ sendMessage(msg);
+ }
+
+ /**
* @hide pending API council approval
*/
public boolean onJsTimeout() {
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index e8c2279..7b91724 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -262,7 +262,7 @@ public final class CookieManager {
if (!mAcceptCookie || uri == null) {
return;
}
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.COOKIE_MANAGER) {
Log.v(LOGTAG, "setCookie: uri: " + uri + " value: " + value);
}
@@ -427,12 +427,12 @@ public final class CookieManager {
}
}
if (ret.length() > 0) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.COOKIE_MANAGER) {
Log.v(LOGTAG, "getCookie: uri: " + uri + " value: " + ret);
}
return ret.toString();
} else {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.COOKIE_MANAGER) {
Log.v(LOGTAG, "getCookie: uri: " + uri
+ " But can't find cookie.");
}
@@ -588,7 +588,7 @@ public final class CookieManager {
Iterator<ArrayList<Cookie>> listIter = cookieLists.iterator();
while (listIter.hasNext() && count < MAX_RAM_COOKIES_COUNT) {
ArrayList<Cookie> list = listIter.next();
- if (WebView.DEBUG) {
+ if (DebugFlags.COOKIE_MANAGER) {
Iterator<Cookie> iter = list.iterator();
while (iter.hasNext() && count < MAX_RAM_COOKIES_COUNT) {
Cookie cookie = iter.next();
@@ -608,7 +608,7 @@ public final class CookieManager {
ArrayList<Cookie> retlist = new ArrayList<Cookie>();
if (mapSize >= MAX_RAM_DOMAIN_COUNT || count >= MAX_RAM_COOKIES_COUNT) {
- if (WebView.DEBUG) {
+ if (DebugFlags.COOKIE_MANAGER) {
Log.v(LOGTAG, count + " cookies used " + byteCount
+ " bytes with " + mapSize + " domains");
}
@@ -616,7 +616,7 @@ public final class CookieManager {
int toGo = mapSize / 10 + 1;
while (toGo-- > 0){
String domain = domains[toGo].toString();
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.COOKIE_MANAGER) {
Log.v(LOGTAG, "delete domain: " + domain
+ " from RAM cache");
}
diff --git a/core/java/android/webkit/CookieSyncManager.java b/core/java/android/webkit/CookieSyncManager.java
index 8d66529..14375d2 100644
--- a/core/java/android/webkit/CookieSyncManager.java
+++ b/core/java/android/webkit/CookieSyncManager.java
@@ -24,30 +24,39 @@ import java.util.ArrayList;
import java.util.Iterator;
/**
- * The class CookieSyncManager is used to synchronize the browser cookies
- * between RAM and FLASH. To get the best performance, browser cookie is saved
- * in RAM. We use a separate thread to sync the cookies between RAM and FLASH on
- * a timer base.
+ * The CookieSyncManager is used to synchronize the browser cookie store
+ * between RAM and permanent storage. To get the best performance, browser cookies are
+ * saved in RAM. A separate thread saves the cookies between, driven by a timer.
* <p>
+ *
* To use the CookieSyncManager, the host application has to call the following
- * when the application starts.
- * <p>
- * CookieSyncManager.createInstance(context)
- * <p>
- * To set up for sync, the host application has to call
- * <p>
- * CookieSyncManager.getInstance().startSync()
+ * when the application starts:
* <p>
- * in its Activity.onResume(), and call
+ *
+ * <pre class="prettyprint">CookieSyncManager.createInstance(context)</pre><p>
+ *
+ * To set up for sync, the host application has to call<p>
+ * <pre class="prettyprint">CookieSyncManager.getInstance().startSync()</pre><p>
+ *
+ * in Activity.onResume(), and call
* <p>
+ *
+ * <pre class="prettyprint">
* CookieSyncManager.getInstance().stopSync()
- * <p>
- * in its Activity.onStop().
- * <p>
+ * </pre><p>
+ *
+ * in Activity.onPause().<p>
+ *
* To get instant sync instead of waiting for the timer to trigger, the host can
* call
* <p>
- * CookieSyncManager.getInstance().sync()
+ * <pre class="prettyprint">CookieSyncManager.getInstance().sync()</pre><p>
+ *
+ * The sync interval is 5 minutes, so you will want to force syncs
+ * manually anyway, for instance in {@link
+ * WebViewClient#onPageFinished}. Note that even sync() happens
+ * asynchronously, so don't do it just as your activity is shutting
+ * down.
*/
public final class CookieSyncManager extends WebSyncManager {
@@ -90,7 +99,7 @@ public final class CookieSyncManager extends WebSyncManager {
}
/**
- * Package level api, called from CookieManager Get all the cookies which
+ * Package level api, called from CookieManager. Get all the cookies which
* matches a given base domain.
* @param domain
* @return A list of Cookie
@@ -161,7 +170,7 @@ public final class CookieSyncManager extends WebSyncManager {
}
protected void syncFromRamToFlash() {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.COOKIE_SYNC_MANAGER) {
Log.v(LOGTAG, "CookieSyncManager::syncFromRamToFlash STARTS");
}
@@ -178,7 +187,7 @@ public final class CookieSyncManager extends WebSyncManager {
CookieManager.getInstance().deleteLRUDomain();
syncFromRamToFlash(lruList);
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.COOKIE_SYNC_MANAGER) {
Log.v(LOGTAG, "CookieSyncManager::syncFromRamToFlash DONE");
}
}
diff --git a/core/java/android/webkit/DataLoader.java b/core/java/android/webkit/DataLoader.java
index dcdc949..6c5d10d 100644
--- a/core/java/android/webkit/DataLoader.java
+++ b/core/java/android/webkit/DataLoader.java
@@ -16,12 +16,10 @@
package android.webkit;
-import org.apache.http.protocol.HTTP;
-
-import android.net.http.Headers;
-
import java.io.ByteArrayInputStream;
+import org.apache.harmony.luni.util.Base64;
+
/**
* This class is a concrete implementation of StreamLoader that uses the
* content supplied as a URL as the source for the stream. The mimetype
@@ -30,8 +28,6 @@ import java.io.ByteArrayInputStream;
*/
class DataLoader extends StreamLoader {
- private String mContentType; // Content mimetype, if supplied in URL
-
/**
* Constructor uses the dataURL as the source for an InputStream
* @param dataUrl data: URL string optionally containing a mimetype
@@ -41,16 +37,20 @@ class DataLoader extends StreamLoader {
super(loadListener);
String url = dataUrl.substring("data:".length());
- String content;
+ byte[] data = null;
int commaIndex = url.indexOf(',');
if (commaIndex != -1) {
- mContentType = url.substring(0, commaIndex);
- content = url.substring(commaIndex + 1);
+ String contentType = url.substring(0, commaIndex);
+ data = url.substring(commaIndex + 1).getBytes();
+ loadListener.parseContentTypeHeader(contentType);
+ if ("base64".equals(loadListener.transferEncoding())) {
+ data = Base64.decode(data);
+ }
} else {
- content = url;
+ data = url.getBytes();
}
- mDataStream = new ByteArrayInputStream(content.getBytes());
- mContentLength = content.length();
+ mDataStream = new ByteArrayInputStream(data);
+ mContentLength = data.length;
}
@Override
@@ -60,10 +60,7 @@ class DataLoader extends StreamLoader {
}
@Override
- protected void buildHeaders(Headers headers) {
- if (mContentType != null) {
- headers.setContentType(mContentType);
- }
+ protected void buildHeaders(android.net.http.Headers h) {
}
/**
diff --git a/core/java/android/webkit/DebugFlags.java b/core/java/android/webkit/DebugFlags.java
new file mode 100644
index 0000000..89cb606
--- /dev/null
+++ b/core/java/android/webkit/DebugFlags.java
@@ -0,0 +1,48 @@
+/*
+ * 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.webkit;
+
+/**
+ * This class is a container for all of the debug flags used in the Java
+ * components of webkit. These flags must be final in order to ensure that
+ * the compiler optimizes the code that uses them out of the final executable.
+ *
+ * The name of each flags maps directly to the name of the class in which that
+ * flag is used.
+ *
+ */
+class DebugFlags {
+
+ public static final boolean BROWSER_FRAME = false;
+ public static final boolean CACHE_MANAGER = false;
+ public static final boolean CALLBACK_PROXY = false;
+ public static final boolean COOKIE_MANAGER = false;
+ public static final boolean COOKIE_SYNC_MANAGER = false;
+ public static final boolean FRAME_LOADER = false;
+ public static final boolean J_WEB_CORE_JAVA_BRIDGE = false;// HIGHLY VERBOSE
+ public static final boolean LOAD_LISTENER = false;
+ public static final boolean NETWORK = false;
+ public static final boolean SSL_ERROR_HANDLER = false;
+ public static final boolean STREAM_LOADER = false;
+ public static final boolean URL_UTIL = false;
+ public static final boolean WEB_BACK_FORWARD_LIST = false;
+ public static final boolean WEB_SETTINGS = false;
+ public static final boolean WEB_SYNC_MANAGER = false;
+ public static final boolean WEB_VIEW = false;
+ public static final boolean WEB_VIEW_CORE = false;
+
+}
diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java
index 6f1b160..c33744e 100644
--- a/core/java/android/webkit/FrameLoader.java
+++ b/core/java/android/webkit/FrameLoader.java
@@ -120,7 +120,7 @@ class FrameLoader {
} else if (handleLocalFile(url, mListener, mSettings)) {
return true;
}
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.FRAME_LOADER) {
Log.v(LOGTAG, "FrameLoader.executeLoad: url protocol not supported:"
+ mListener.url());
}
@@ -180,7 +180,7 @@ class FrameLoader {
return true;
}
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.FRAME_LOADER) {
Log.v(LOGTAG, "FrameLoader: http " + mMethod + " load for: "
+ mListener.url());
}
@@ -211,7 +211,7 @@ class FrameLoader {
* setup a load from the byte stream in a CacheResult.
*/
private void startCacheLoad(CacheResult result) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.FRAME_LOADER) {
Log.v(LOGTAG, "FrameLoader: loading from cache: "
+ mListener.url());
}
@@ -285,7 +285,7 @@ class FrameLoader {
// of it's state. If it is not in the cache, then go to the
// network.
case WebSettings.LOAD_CACHE_ELSE_NETWORK: {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.FRAME_LOADER) {
Log.v(LOGTAG, "FrameLoader: checking cache: "
+ mListener.url());
}
diff --git a/core/java/android/webkit/HttpDateTime.java b/core/java/android/webkit/HttpDateTime.java
index c6ec2d2..48b2081 100644
--- a/core/java/android/webkit/HttpDateTime.java
+++ b/core/java/android/webkit/HttpDateTime.java
@@ -47,14 +47,16 @@ class HttpDateTime {
* Wdy, DD Mon YYYY HH:MM:SS
* Wdy Mon (SP)D HH:MM:SS YYYY
* Wdy Mon DD HH:MM:SS YYYY GMT
+ *
+ * HH can be H if the first digit is zero.
*/
private static final String HTTP_DATE_RFC_REGEXP =
"([0-9]{1,2})[- ]([A-Za-z]{3,3})[- ]([0-9]{2,4})[ ]"
- + "([0-9][0-9]:[0-9][0-9]:[0-9][0-9])";
+ + "([0-9]{1,2}:[0-9][0-9]:[0-9][0-9])";
private static final String HTTP_DATE_ANSIC_REGEXP =
"[ ]([A-Za-z]{3,3})[ ]+([0-9]{1,2})[ ]"
- + "([0-9][0-9]:[0-9][0-9]:[0-9][0-9])[ ]([0-9]{2,4})";
+ + "([0-9]{1,2}:[0-9][0-9]:[0-9][0-9])[ ]([0-9]{2,4})";
/**
* The compiled version of the HTTP-date regular expressions.
@@ -65,6 +67,12 @@ class HttpDateTime {
Pattern.compile(HTTP_DATE_ANSIC_REGEXP);
private static class TimeOfDay {
+ TimeOfDay(int h, int m, int s) {
+ this.hour = h;
+ this.minute = m;
+ this.second = s;
+ }
+
int hour;
int minute;
int second;
@@ -76,7 +84,7 @@ class HttpDateTime {
int date = 1;
int month = Calendar.JANUARY;
int year = 1970;
- TimeOfDay timeOfDay = new TimeOfDay();
+ TimeOfDay timeOfDay;
Matcher rfcMatcher = HTTP_DATE_RFC_PATTERN.matcher(timeString);
if (rfcMatcher.find()) {
@@ -183,13 +191,22 @@ class HttpDateTime {
}
private static TimeOfDay getTime(String timeString) {
- TimeOfDay time = new TimeOfDay();
- time.hour = (timeString.charAt(0) - '0') * 10
- + (timeString.charAt(1) - '0');
- time.minute = (timeString.charAt(3) - '0') * 10
- + (timeString.charAt(4) - '0');
- time.second = (timeString.charAt(6) - '0') * 10
- + (timeString.charAt(7) - '0');
- return time;
+ // HH might be H
+ int i = 0;
+ int hour = timeString.charAt(i++) - '0';
+ if (timeString.charAt(i) != ':')
+ hour = hour * 10 + (timeString.charAt(i++) - '0');
+ // Skip ':'
+ i++;
+
+ int minute = (timeString.charAt(i++) - '0') * 10
+ + (timeString.charAt(i++) - '0');
+ // Skip ':'
+ i++;
+
+ int second = (timeString.charAt(i++) - '0') * 10
+ + (timeString.charAt(i++) - '0');
+
+ return new TimeOfDay(hour, minute, second);
}
}
diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
index 2a84683..878b690 100644
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ b/core/java/android/webkit/JWebCoreJavaBridge.java
@@ -33,9 +33,16 @@ final class JWebCoreJavaBridge extends Handler {
// Instant timer is used to implement a timer that needs to fire almost
// immediately.
private boolean mHasInstantTimer;
+
// Reference count the pause/resume of timers
private int mPauseTimerRefCount;
+ private boolean mTimerPaused;
+ private boolean mHasDeferredTimers;
+
+ /* package */
+ static final int REFRESH_PLUGINS = 100;
+
/**
* Construct a new JWebCoreJavaBridge to interface with
* WebCore timers and cookies.
@@ -50,6 +57,17 @@ final class JWebCoreJavaBridge extends Handler {
}
/**
+ * Call native timer callbacks.
+ */
+ private void fireSharedTimer() {
+ PerfChecker checker = new PerfChecker();
+ // clear the flag so that sharedTimerFired() can set a new timer
+ mHasInstantTimer = false;
+ sharedTimerFired();
+ checker.responseAlert("sharedTimer");
+ }
+
+ /**
* handleMessage
* @param msg The dispatched message.
*
@@ -59,16 +77,21 @@ final class JWebCoreJavaBridge extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case TIMER_MESSAGE: {
- PerfChecker checker = new PerfChecker();
- // clear the flag so that sharedTimerFired() can set a new timer
- mHasInstantTimer = false;
- sharedTimerFired();
- checker.responseAlert("sharedTimer");
+ if (mTimerPaused) {
+ mHasDeferredTimers = true;
+ } else {
+ fireSharedTimer();
+ }
break;
}
case FUNCPTR_MESSAGE:
nativeServiceFuncPtrQueue();
break;
+ case REFRESH_PLUGINS:
+ nativeUpdatePluginDirectories(PluginManager.getInstance(null)
+ .getPluginDirecoties(), ((Boolean) msg.obj)
+ .booleanValue());
+ break;
}
}
@@ -85,7 +108,8 @@ final class JWebCoreJavaBridge extends Handler {
*/
public void pause() {
if (--mPauseTimerRefCount == 0) {
- setDeferringTimers(true);
+ mTimerPaused = true;
+ mHasDeferredTimers = false;
}
}
@@ -94,7 +118,11 @@ final class JWebCoreJavaBridge extends Handler {
*/
public void resume() {
if (++mPauseTimerRefCount == 1) {
- setDeferringTimers(false);
+ mTimerPaused = false;
+ if (mHasDeferredTimers) {
+ mHasDeferredTimers = false;
+ fireSharedTimer();
+ }
}
}
@@ -151,11 +179,18 @@ final class JWebCoreJavaBridge extends Handler {
}
/**
+ * Returns an array of plugin directoies
+ */
+ private String[] getPluginDirectories() {
+ return PluginManager.getInstance(null).getPluginDirecoties();
+ }
+
+ /**
* setSharedTimer
* @param timemillis The relative time when the timer should fire
*/
private void setSharedTimer(long timemillis) {
- if (WebView.LOGV_ENABLED) Log.v(LOGTAG, "setSharedTimer " + timemillis);
+ if (DebugFlags.J_WEB_CORE_JAVA_BRIDGE) Log.v(LOGTAG, "setSharedTimer " + timemillis);
if (timemillis <= 0) {
// we don't accumulate the sharedTimer unless it is a delayed
@@ -179,16 +214,18 @@ final class JWebCoreJavaBridge extends Handler {
* Stop the shared timer.
*/
private void stopSharedTimer() {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.J_WEB_CORE_JAVA_BRIDGE) {
Log.v(LOGTAG, "stopSharedTimer removing all timers");
}
removeMessages(TIMER_MESSAGE);
mHasInstantTimer = false;
+ mHasDeferredTimers = false;
}
private native void nativeConstructor();
private native void nativeFinalize();
private native void sharedTimerFired();
- private native void setDeferringTimers(boolean defer);
+ private native void nativeUpdatePluginDirectories(String[] directories,
+ boolean reload);
public native void setNetworkOnLine(boolean online);
}
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index d583eb1..1ebdb79 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -43,8 +43,6 @@ import java.util.Vector;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
-import org.apache.commons.codec.binary.Base64;
-
class LoadListener extends Handler implements EventHandler {
private static final String LOGTAG = "webkit";
@@ -133,15 +131,13 @@ class LoadListener extends Handler implements EventHandler {
LoadListener(Context context, BrowserFrame frame, String url,
int nativeLoader, boolean synchronous, boolean isMainPageLoader) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener constructor url=" + url);
}
mContext = context;
mBrowserFrame = frame;
setUrl(url);
mNativeLoader = nativeLoader;
- mMimeType = "";
- mEncoding = "";
mSynchronous = synchronous;
if (synchronous) {
mMessageQueue = new Vector<Message>();
@@ -284,7 +280,7 @@ class LoadListener extends Handler implements EventHandler {
* directly
*/
public void headers(Headers headers) {
- if (WebView.LOGV_ENABLED) Log.v(LOGTAG, "LoadListener.headers");
+ if (DebugFlags.LOAD_LISTENER) Log.v(LOGTAG, "LoadListener.headers");
sendMessageInternal(obtainMessage(MSG_CONTENT_HEADERS, headers));
}
@@ -292,8 +288,6 @@ class LoadListener extends Handler implements EventHandler {
private void handleHeaders(Headers headers) {
if (mCancelled) return;
mHeaders = headers;
- mMimeType = "";
- mEncoding = "";
ArrayList<String> cookies = headers.getSetCookie();
for (int i = 0; i < cookies.size(); ++i) {
@@ -313,24 +307,21 @@ class LoadListener extends Handler implements EventHandler {
// If we have one of "generic" MIME types, try to deduce
// the right MIME type from the file extension (if any):
- if (mMimeType.equalsIgnoreCase("text/plain") ||
- mMimeType.equalsIgnoreCase("application/octet-stream")) {
+ if (mMimeType.equals("text/plain") ||
+ mMimeType.equals("application/octet-stream")) {
String newMimeType = guessMimeTypeFromExtension();
if (newMimeType != null) {
mMimeType = newMimeType;
}
- } else if (mMimeType.equalsIgnoreCase("text/vnd.wap.wml")) {
+ } else if (mMimeType.equals("text/vnd.wap.wml")) {
// As we don't support wml, render it as plain text
mMimeType = "text/plain";
} else {
- // XXX: Until the servers send us either correct xhtml or
- // text/html, treat application/xhtml+xml as text/html.
// It seems that xhtml+xml and vnd.wap.xhtml+xml mime
// subtypes are used interchangeably. So treat them the same.
- if (mMimeType.equalsIgnoreCase("application/xhtml+xml") ||
- mMimeType.equals("application/vnd.wap.xhtml+xml")) {
- mMimeType = "text/html";
+ if (mMimeType.equals("application/vnd.wap.xhtml+xml")) {
+ mMimeType = "application/xhtml+xml";
}
}
} else {
@@ -431,7 +422,7 @@ class LoadListener extends Handler implements EventHandler {
*/
public void status(int majorVersion, int minorVersion,
int code, /* Status-Code value */ String reasonPhrase) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener: from: " + mUrl
+ " major: " + majorVersion
+ " minor: " + minorVersion
@@ -445,6 +436,9 @@ class LoadListener extends Handler implements EventHandler {
status.put("reason", reasonPhrase);
// New status means new data. Clear the old.
mDataBuilder.clear();
+ mMimeType = "";
+ mEncoding = "";
+ mTransferEncoding = "";
sendMessageInternal(obtainMessage(MSG_STATUS, status));
}
@@ -488,7 +482,7 @@ class LoadListener extends Handler implements EventHandler {
* directly
*/
public void error(int id, String description) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener.error url:" +
url() + " id:" + id + " description:" + description);
}
@@ -516,23 +510,10 @@ class LoadListener extends Handler implements EventHandler {
* mDataBuilder is a thread-safe structure.
*/
public void data(byte[] data, int length) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener.data(): url: " + url());
}
- // Decode base64 data
- // Note: It's fine that we only decode base64 here and not in the other
- // data call because the only caller of the stream version is not
- // base64 encoded.
- if ("base64".equalsIgnoreCase(mTransferEncoding)) {
- if (length < data.length) {
- byte[] trimmedData = new byte[length];
- System.arraycopy(data, 0, trimmedData, 0, length);
- data = trimmedData;
- }
- data = Base64.decodeBase64(data);
- length = data.length;
- }
// Synchronize on mData because commitLoad may write mData to WebCore
// and we don't want to replace mData or mDataLength at the same time
// as a write.
@@ -554,7 +535,7 @@ class LoadListener extends Handler implements EventHandler {
* directly
*/
public void endData() {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener.endData(): url: " + url());
}
sendMessageInternal(obtainMessage(MSG_CONTENT_FINISHED));
@@ -607,7 +588,7 @@ class LoadListener extends Handler implements EventHandler {
// before calling it.
if (mCacheLoader != null) {
mCacheLoader.load();
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener cache load url=" + url());
}
return;
@@ -657,7 +638,7 @@ class LoadListener extends Handler implements EventHandler {
CacheManager.HEADER_KEY_IFNONEMATCH) &&
!headers.containsKey(
CacheManager.HEADER_KEY_IFMODIFIEDSINCE)) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "FrameLoader: HTTP URL in cache " +
"and usable: " + url());
}
@@ -676,7 +657,7 @@ class LoadListener extends Handler implements EventHandler {
* directly
*/
public void handleSslErrorRequest(SslError error) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG,
"LoadListener.handleSslErrorRequest(): url:" + url() +
" primary error: " + error.getPrimaryError() +
@@ -742,7 +723,7 @@ class LoadListener extends Handler implements EventHandler {
* are null, cancel the request.
*/
void handleAuthResponse(String username, String password) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener.handleAuthResponse: url: " + mUrl
+ " username: " + username
+ " password: " + password);
@@ -839,7 +820,7 @@ class LoadListener extends Handler implements EventHandler {
}
void attachRequestHandle(RequestHandle requestHandle) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener.attachRequestHandle(): " +
"requestHandle: " + requestHandle);
}
@@ -847,7 +828,7 @@ class LoadListener extends Handler implements EventHandler {
}
void detachRequestHandle() {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener.detachRequestHandle(): " +
"requestHandle: " + mRequestHandle);
}
@@ -886,7 +867,7 @@ class LoadListener extends Handler implements EventHandler {
*/
static boolean willLoadFromCache(String url) {
boolean inCache = CacheManager.getCacheFile(url, null) != null;
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "willLoadFromCache: " + url + " in cache: " +
inCache);
}
@@ -907,6 +888,10 @@ class LoadListener extends Handler implements EventHandler {
return mMimeType;
}
+ String transferEncoding() {
+ return mTransferEncoding;
+ }
+
/*
* Return the size of the content being downloaded. This represents the
* full content size, even under the situation where the download has been
@@ -1056,7 +1041,7 @@ class LoadListener extends Handler implements EventHandler {
* EventHandler's method call.
*/
public void cancel() {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
if (mRequestHandle == null) {
Log.v(LOGTAG, "LoadListener.cancel(): no requestHandle");
} else {
@@ -1188,7 +1173,7 @@ class LoadListener extends Handler implements EventHandler {
tearDown();
}
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener.onRedirect(): redirect to: " +
redirectTo);
}
@@ -1201,8 +1186,8 @@ class LoadListener extends Handler implements EventHandler {
private static final Pattern CONTENT_TYPE_PATTERN =
Pattern.compile("^((?:[xX]-)?[a-zA-Z\\*]+/[\\w\\+\\*-]+[\\.[\\w\\+-]+]*)$");
- private void parseContentTypeHeader(String contentType) {
- if (WebView.LOGV_ENABLED) {
+ /* package */ void parseContentTypeHeader(String contentType) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener.parseContentTypeHeader: " +
"contentType: " + contentType);
}
@@ -1223,13 +1208,14 @@ class LoadListener extends Handler implements EventHandler {
mEncoding = contentType.substring(i + 1);
}
// Trim excess whitespace.
- mEncoding = mEncoding.trim();
+ mEncoding = mEncoding.trim().toLowerCase();
if (i < contentType.length() - 1) {
// for data: uri the mimeType and encoding have
// the form image/jpeg;base64 or text/plain;charset=utf-8
// or text/html;charset=utf-8;base64
- mTransferEncoding = contentType.substring(i + 1).trim();
+ mTransferEncoding =
+ contentType.substring(i + 1).trim().toLowerCase();
}
} else {
mMimeType = contentType;
@@ -1249,6 +1235,8 @@ class LoadListener extends Handler implements EventHandler {
guessMimeType();
}
}
+ // Ensure mMimeType is lower case.
+ mMimeType = mMimeType.toLowerCase();
}
/**
@@ -1379,7 +1367,7 @@ class LoadListener extends Handler implements EventHandler {
mMimeType = "text/html";
String newMimeType = guessMimeTypeFromExtension();
if (newMimeType != null) {
- mMimeType = newMimeType;
+ mMimeType = newMimeType;
}
}
}
@@ -1389,23 +1377,12 @@ class LoadListener extends Handler implements EventHandler {
*/
private String guessMimeTypeFromExtension() {
// PENDING: need to normalize url
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "guessMimeTypeFromExtension: mURL = " + mUrl);
}
- String mimeType =
- MimeTypeMap.getSingleton().getMimeTypeFromExtension(
- MimeTypeMap.getFileExtensionFromUrl(mUrl));
-
- if (mimeType != null) {
- // XXX: Until the servers send us either correct xhtml or
- // text/html, treat application/xhtml+xml as text/html.
- if (mimeType.equals("application/xhtml+xml")) {
- mimeType = "text/html";
- }
- }
-
- return mimeType;
+ return MimeTypeMap.getSingleton().getMimeTypeFromExtension(
+ MimeTypeMap.getFileExtensionFromUrl(mUrl));
}
/**
@@ -1424,7 +1401,7 @@ class LoadListener extends Handler implements EventHandler {
* Cycle through our messages for synchronous loads.
*/
/* package */ void loadSynchronousMessages() {
- if (WebView.DEBUG && !mSynchronous) {
+ if (DebugFlags.LOAD_LISTENER && !mSynchronous) {
throw new AssertionError();
}
// Note: this can be called twice if it is a synchronous network load,
diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java
index 85c2275..096f38a 100644
--- a/core/java/android/webkit/MimeTypeMap.java
+++ b/core/java/android/webkit/MimeTypeMap.java
@@ -358,6 +358,7 @@ public /* package */ class MimeTypeMap {
sMimeTypeMap.loadEntry("application/x-x509-ca-cert", "crt", false);
sMimeTypeMap.loadEntry("application/x-xcf", "xcf", false);
sMimeTypeMap.loadEntry("application/x-xfig", "fig", false);
+ sMimeTypeMap.loadEntry("application/xhtml+xml", "xhtml", false);
sMimeTypeMap.loadEntry("audio/basic", "snd", false);
sMimeTypeMap.loadEntry("audio/midi", "mid", false);
sMimeTypeMap.loadEntry("audio/midi", "midi", false);
diff --git a/core/java/android/webkit/Network.java b/core/java/android/webkit/Network.java
index c9b80ce..8c2b09b 100644
--- a/core/java/android/webkit/Network.java
+++ b/core/java/android/webkit/Network.java
@@ -132,7 +132,7 @@ class Network {
* XXX: Must be created in the same thread as WebCore!!!!!
*/
private Network(Context context) {
- if (WebView.DEBUG) {
+ if (DebugFlags.NETWORK) {
Assert.assertTrue(Thread.currentThread().
getName().equals(WebViewCore.THREAD_NAME));
}
@@ -232,7 +232,7 @@ class Network {
* connecting through the proxy.
*/
public synchronized void setProxyUsername(String proxyUsername) {
- if (WebView.DEBUG) {
+ if (DebugFlags.NETWORK) {
Assert.assertTrue(isValidProxySet());
}
@@ -252,7 +252,7 @@ class Network {
* connecting through the proxy.
*/
public synchronized void setProxyPassword(String proxyPassword) {
- if (WebView.DEBUG) {
+ if (DebugFlags.NETWORK) {
Assert.assertTrue(isValidProxySet());
}
@@ -266,7 +266,7 @@ class Network {
* @return True iff succeeds.
*/
public boolean saveState(Bundle outState) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.NETWORK) {
Log.v(LOGTAG, "Network.saveState()");
}
@@ -280,7 +280,7 @@ class Network {
* @return True iff succeeds.
*/
public boolean restoreState(Bundle inState) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.NETWORK) {
Log.v(LOGTAG, "Network.restoreState()");
}
@@ -300,7 +300,7 @@ class Network {
* @param loader The loader that resulted in SSL errors.
*/
public void handleSslErrorRequest(LoadListener loader) {
- if (WebView.DEBUG) Assert.assertNotNull(loader);
+ if (DebugFlags.NETWORK) Assert.assertNotNull(loader);
if (loader != null) {
mSslErrorHandler.handleSslErrorRequest(loader);
}
@@ -313,7 +313,7 @@ class Network {
* authentication request.
*/
public void handleAuthRequest(LoadListener loader) {
- if (WebView.DEBUG) Assert.assertNotNull(loader);
+ if (DebugFlags.NETWORK) Assert.assertNotNull(loader);
if (loader != null) {
mHttpAuthHandler.handleAuthRequest(loader);
}
diff --git a/core/java/android/webkit/PluginManager.java b/core/java/android/webkit/PluginManager.java
new file mode 100644
index 0000000..e4a44b9
--- /dev/null
+++ b/core/java/android/webkit/PluginManager.java
@@ -0,0 +1,157 @@
+/*
+ * 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.webkit;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.Signature;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.util.Log;
+
+/**
+ * Class for managing the relationship between the {@link WebView} and installed
+ * plugins in the system. You can find this class through
+ * {@link PluginManager#getInstance}.
+ *
+ * @hide pending API solidification
+ */
+public class PluginManager {
+
+ /**
+ * Service Action: A plugin wishes to be loaded in the WebView must provide
+ * {@link android.content.IntentFilter IntentFilter} that accepts this
+ * action in their AndroidManifest.xml.
+ * <p>
+ * TODO: we may change this to a new PLUGIN_ACTION if this is going to be
+ * public.
+ */
+ @SdkConstant(SdkConstantType.SERVICE_ACTION)
+ public static final String PLUGIN_ACTION = "android.webkit.PLUGIN";
+
+ /**
+ * A plugin wishes to be loaded in the WebView must provide this permission
+ * in their AndroidManifest.xml.
+ */
+ public static final String PLUGIN_PERMISSION = "android.webkit.permission.PLUGIN";
+
+ private static final String LOGTAG = "webkit";
+
+ private static PluginManager mInstance = null;
+
+ private final Context mContext;
+
+ private PluginManager(Context context) {
+ mContext = context;
+ }
+
+ public static synchronized PluginManager getInstance(Context context) {
+ if (mInstance == null) {
+ if (context == null) {
+ throw new IllegalStateException(
+ "First call to PluginManager need a valid context.");
+ }
+ mInstance = new PluginManager(context);
+ }
+ return mInstance;
+ }
+
+ /**
+ * Signal the WebCore thread to refresh its list of plugins. Use this if the
+ * directory contents of one of the plugin directories has been modified and
+ * needs its changes reflecting. May cause plugin load and/or unload.
+ *
+ * @param reloadOpenPages Set to true to reload all open pages.
+ */
+ public void refreshPlugins(boolean reloadOpenPages) {
+ BrowserFrame.sJavaBridge.obtainMessage(
+ JWebCoreJavaBridge.REFRESH_PLUGINS, reloadOpenPages)
+ .sendToTarget();
+ }
+
+ String[] getPluginDirecoties() {
+ ArrayList<String> directories = new ArrayList<String>();
+ PackageManager pm = mContext.getPackageManager();
+ List<ResolveInfo> plugins = pm.queryIntentServices(new Intent(
+ PLUGIN_ACTION), PackageManager.GET_SERVICES);
+ for (ResolveInfo info : plugins) {
+ ServiceInfo serviceInfo = info.serviceInfo;
+ if (serviceInfo == null) {
+ Log.w(LOGTAG, "Ignore bad plugin");
+ continue;
+ }
+ PackageInfo pkgInfo;
+ try {
+ pkgInfo = pm.getPackageInfo(serviceInfo.packageName,
+ PackageManager.GET_PERMISSIONS
+ | PackageManager.GET_SIGNATURES);
+ } catch (NameNotFoundException e) {
+ Log.w(LOGTAG, "Cant find plugin: " + serviceInfo.packageName);
+ continue;
+ }
+ if (pkgInfo == null) {
+ continue;
+ }
+ String directory = pkgInfo.applicationInfo.dataDir + "/lib";
+ if (directories.contains(directory)) {
+ continue;
+ }
+ String permissions[] = pkgInfo.requestedPermissions;
+ if (permissions == null) {
+ continue;
+ }
+ boolean permissionOk = false;
+ for (String permit : permissions) {
+ if (PLUGIN_PERMISSION.equals(permit)) {
+ permissionOk = true;
+ break;
+ }
+ }
+ if (!permissionOk) {
+ continue;
+ }
+ Signature signatures[] = pkgInfo.signatures;
+ if (signatures == null) {
+ continue;
+ }
+ boolean signatureMatch = false;
+ for (Signature signature : signatures) {
+ // TODO: check signature against Google provided one
+ signatureMatch = true;
+ break;
+ }
+ if (!signatureMatch) {
+ continue;
+ }
+ directories.add(directory);
+ }
+ // hack for gears for now
+ String gears = mContext.getDir("plugins", 0).getPath();
+ if (!directories.contains(gears)) {
+ directories.add(gears);
+ }
+ return directories.toArray(new String[directories.size()]);
+ }
+}
diff --git a/core/java/android/webkit/SslErrorHandler.java b/core/java/android/webkit/SslErrorHandler.java
index 5f84bbe..cc1e750 100644
--- a/core/java/android/webkit/SslErrorHandler.java
+++ b/core/java/android/webkit/SslErrorHandler.java
@@ -120,7 +120,7 @@ public class SslErrorHandler extends Handler {
* Handles SSL error(s) on the way up to the user.
*/
/* package */ synchronized void handleSslErrorRequest(LoadListener loader) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.SSL_ERROR_HANDLER) {
Log.v(LOGTAG, "SslErrorHandler.handleSslErrorRequest(): " +
"url=" + loader.url());
}
@@ -157,14 +157,14 @@ public class SslErrorHandler extends Handler {
SslError error = loader.sslError();
- if (WebView.DEBUG) {
+ if (DebugFlags.SSL_ERROR_HANDLER) {
Assert.assertNotNull(error);
}
int primary = error.getPrimaryError();
String host = loader.host();
- if (WebView.DEBUG) {
+ if (DebugFlags.SSL_ERROR_HANDLER) {
Assert.assertTrue(host != null && primary != 0);
}
@@ -205,11 +205,11 @@ public class SslErrorHandler extends Handler {
*/
/* package */ synchronized void handleSslErrorResponse(boolean proceed) {
LoadListener loader = mLoaderQueue.poll();
- if (WebView.DEBUG) {
+ if (DebugFlags.SSL_ERROR_HANDLER) {
Assert.assertNotNull(loader);
}
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.SSL_ERROR_HANDLER) {
Log.v(LOGTAG, "SslErrorHandler.handleSslErrorResponse():"
+ " proceed: " + proceed
+ " url:" + loader.url());
@@ -221,13 +221,13 @@ public class SslErrorHandler extends Handler {
int primary = loader.sslError().getPrimaryError();
String host = loader.host();
- if (WebView.DEBUG) {
+ if (DebugFlags.SSL_ERROR_HANDLER) {
Assert.assertTrue(host != null && primary != 0);
}
boolean hasKey = mSslPrefTable.containsKey(host);
if (!hasKey ||
primary > mSslPrefTable.getInt(host)) {
- mSslPrefTable.putInt(host, new Integer(primary));
+ mSslPrefTable.putInt(host, primary);
}
}
loader.handleSslErrorResponse(proceed);
diff --git a/core/java/android/webkit/StreamLoader.java b/core/java/android/webkit/StreamLoader.java
index 705157c..eab3350 100644
--- a/core/java/android/webkit/StreamLoader.java
+++ b/core/java/android/webkit/StreamLoader.java
@@ -102,7 +102,7 @@ abstract class StreamLoader extends Handler {
// to pass data to the loader
mData = new byte[8192];
sendHeaders();
- while (!sendData());
+ while (!sendData() && !mHandler.cancelled());
closeStreamAndSendEndData();
mHandler.loadSynchronousMessages();
}
@@ -113,9 +113,13 @@ abstract class StreamLoader extends Handler {
* @see android.os.Handler#handleMessage(android.os.Message)
*/
public void handleMessage(Message msg) {
- if (WebView.DEBUG && mHandler.isSynchronous()) {
+ if (DebugFlags.STREAM_LOADER && mHandler.isSynchronous()) {
throw new AssertionError();
}
+ if (mHandler.cancelled()) {
+ closeStreamAndSendEndData();
+ return;
+ }
switch(msg.what) {
case MSG_STATUS:
if (setupStreamAndSendStatus()) {
diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java
index d6ac3e9..de70fc2 100644
--- a/core/java/android/webkit/URLUtil.java
+++ b/core/java/android/webkit/URLUtil.java
@@ -61,7 +61,7 @@ public final class URLUtil {
webAddress = new WebAddress(inUrl);
} catch (ParseException ex) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.URL_UTIL) {
Log.v(LOGTAG, "smartUrlFilter: failed to parse url = " + inUrl);
}
return retVal;
diff --git a/core/java/android/webkit/WebBackForwardList.java b/core/java/android/webkit/WebBackForwardList.java
index ffd6a11..62a5531 100644
--- a/core/java/android/webkit/WebBackForwardList.java
+++ b/core/java/android/webkit/WebBackForwardList.java
@@ -137,7 +137,7 @@ public class WebBackForwardList implements Cloneable, Serializable {
// when removing the first item, we can assert that the index is 0.
// This lets us change the current index without having to query the
// native BackForwardList.
- if (WebView.DEBUG && (index != 0)) {
+ if (DebugFlags.WEB_BACK_FORWARD_LIST && (index != 0)) {
throw new AssertionError();
}
final WebHistoryItem h = mArray.remove(index);
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 9d9763c..754b1d9 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -158,6 +158,23 @@ public class WebChromeClient {
return false;
}
+ /**
+ * Tell the client that the database quota for the origin has been exceeded.
+ * @param url The URL that triggered the notification
+ * @param databaseIdentifier The identifier of the database that caused the
+ * quota overflow.
+ * @param currentQuota The current quota for the origin.
+ * @param quotaUpdater A callback to inform the WebCore thread that a new
+ * quota is available. This callback must always be executed at some
+ * point to ensure that the sleeping WebCore thread is woken up.
+ */
+ public void onExceededDatabaseQuota(String url, String databaseIdentifier,
+ long currentQuota, WebStorage.QuotaUpdater quotaUpdater) {
+ // This default implementation passes the current quota back to WebCore.
+ // WebCore will interpret this that new quota was declined.
+ quotaUpdater.updateQuota(currentQuota);
+ }
+
/**
* Tell the client that a JavaScript execution timeout has occured. And the
* client may decide whether or not to interrupt the execution. If the
@@ -172,4 +189,15 @@ public class WebChromeClient {
public boolean onJsTimeout() {
return true;
}
+
+ /**
+ * Add a JavaScript error message to the console. Clients should override
+ * this to process the log message as they see fit.
+ * @param message The error message to report.
+ * @param lineNumber The line number of the error.
+ * @param sourceID The name of the source file that caused the error.
+ * @hide pending API council.
+ */
+ public void addMessageToConsole(String message, int lineNumber, String sourceID) {
+ }
}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index dcba943..ea186fd 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -111,9 +111,13 @@ public class WebSettings {
private boolean mSyncPending = false;
// Custom handler that queues messages until the WebCore thread is active.
private final EventHandler mEventHandler;
+
// Private settings so we don't have to go into native code to
// retrieve the values. After setXXX, postSync() needs to be called.
- // XXX: The default values need to match those in WebSettings.cpp
+ //
+ // The default values need to match those in WebSettings.cpp
+ // If the defaults change, please also update the JavaDocs so developers
+ // know what they are.
private LayoutAlgorithm mLayoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS;
private Context mContext;
private TextSize mTextSize = TextSize.NORMAL;
@@ -127,7 +131,6 @@ public class WebSettings {
private String mUserAgent;
private boolean mUseDefaultUserAgent;
private String mAcceptLanguage;
- private String mPluginsPath = "";
private int mMinimumFontSize = 8;
private int mMinimumLogicalFontSize = 8;
private int mDefaultFontSize = 16;
@@ -137,6 +140,7 @@ public class WebSettings {
private boolean mBlockNetworkLoads;
private boolean mJavaScriptEnabled = false;
private boolean mPluginsEnabled = false;
+ private long mWebStorageDefaultQuota = 0;
private boolean mJavaScriptCanOpenWindowsAutomatically = false;
private boolean mUseDoubleTree = false;
private boolean mUseWideViewport = false;
@@ -155,6 +159,10 @@ public class WebSettings {
private boolean mSupportZoom = true;
private boolean mBuiltInZoomControls = false;
private boolean mAllowFileAccess = true;
+ private String mDatabasePath = "";
+ private boolean mDatabaseEnabled = false;
+ private String mAppCachePath = "";
+ private boolean mAppCacheEnabled = false;
// Class to handle messages before WebCore is ready.
private class EventHandler {
@@ -461,24 +469,21 @@ public class WebSettings {
}
/**
- * Tell the WebView to use the double tree rendering algorithm.
- * @param use True if the WebView is to use double tree rendering, false
- * otherwise.
+ * @deprecated This setting controlled a rendering optimization
+ * that is no longer present. Setting it now has no effect.
*/
+ @Deprecated
public synchronized void setUseDoubleTree(boolean use) {
- if (mUseDoubleTree != use) {
- mUseDoubleTree = use;
- postSync();
- }
+ return;
}
/**
- * Return true if the WebView is using the double tree rendering algorithm.
- * @return True if the WebView is using the double tree rendering
- * algorithm.
+ * @deprecated This setting controlled a rendering optimization
+ * that is no longer present. Setting it now has no effect.
*/
+ @Deprecated
public synchronized boolean getUseDoubleTree() {
- return mUseDoubleTree;
+ return false;
}
/**
@@ -583,7 +588,7 @@ public class WebSettings {
}
/**
- * Return the current layout algorithm.
+ * Return the current layout algorithm. The default is NARROW_COLUMNS.
* @return LayoutAlgorithm enum value describing the layout algorithm
* being used.
* @see WebSettings.LayoutAlgorithm
@@ -604,7 +609,7 @@ public class WebSettings {
}
/**
- * Get the standard font family name.
+ * Get the standard font family name. The default is "sans-serif".
* @return The standard font family name as a string.
*/
public synchronized String getStandardFontFamily() {
@@ -623,7 +628,7 @@ public class WebSettings {
}
/**
- * Get the fixed font family name.
+ * Get the fixed font family name. The default is "monospace".
* @return The fixed font family name as a string.
*/
public synchronized String getFixedFontFamily() {
@@ -650,7 +655,7 @@ public class WebSettings {
}
/**
- * Set the serif font family name.
+ * Set the serif font family name. The default is "sans-serif".
* @param font A font family name.
*/
public synchronized void setSerifFontFamily(String font) {
@@ -661,7 +666,7 @@ public class WebSettings {
}
/**
- * Get the serif font family name.
+ * Get the serif font family name. The default is "serif".
* @return The serif font family name as a string.
*/
public synchronized String getSerifFontFamily() {
@@ -680,7 +685,7 @@ public class WebSettings {
}
/**
- * Get the cursive font family name.
+ * Get the cursive font family name. The default is "cursive".
* @return The cursive font family name as a string.
*/
public synchronized String getCursiveFontFamily() {
@@ -699,7 +704,7 @@ public class WebSettings {
}
/**
- * Get the fantasy font family name.
+ * Get the fantasy font family name. The default is "fantasy".
* @return The fantasy font family name as a string.
*/
public synchronized String getFantasyFontFamily() {
@@ -720,7 +725,7 @@ public class WebSettings {
}
/**
- * Get the minimum font size.
+ * Get the minimum font size. The default is 8.
* @return A non-negative integer between 1 and 72.
*/
public synchronized int getMinimumFontSize() {
@@ -741,7 +746,7 @@ public class WebSettings {
}
/**
- * Get the minimum logical font size.
+ * Get the minimum logical font size. The default is 8.
* @return A non-negative integer between 1 and 72.
*/
public synchronized int getMinimumLogicalFontSize() {
@@ -762,7 +767,7 @@ public class WebSettings {
}
/**
- * Get the default font size.
+ * Get the default font size. The default is 16.
* @return A non-negative integer between 1 and 72.
*/
public synchronized int getDefaultFontSize() {
@@ -783,7 +788,7 @@ public class WebSettings {
}
/**
- * Get the default fixed font size.
+ * Get the default fixed font size. The default is 16.
* @return A non-negative integer between 1 and 72.
*/
public synchronized int getDefaultFixedFontSize() {
@@ -803,6 +808,7 @@ public class WebSettings {
/**
* Return true if the WebView will load image resources automatically.
+ * The default is true.
* @return True if the WebView loads images automatically.
*/
public synchronized boolean getLoadsImagesAutomatically() {
@@ -822,16 +828,16 @@ public class WebSettings {
}
/**
- * Return true if the WebView will block network image.
+ * Return true if the WebView will block network image. The default is false.
* @return True if the WebView blocks network image.
*/
public synchronized boolean getBlockNetworkImage() {
return mBlockNetworkImage;
}
-
+
/**
* @hide
- * Tell the WebView to block all network load requests.
+ * Tell the WebView to block all network load requests.
* @param flag True if the WebView should block all network loads
*/
public synchronized void setBlockNetworkLoads(boolean flag) {
@@ -844,13 +850,14 @@ public class WebSettings {
/**
* @hide
* Return true if the WebView will block all network loads.
+ * The default is false.
* @return True if the WebView blocks all network loads.
*/
public synchronized boolean getBlockNetworkLoads() {
return mBlockNetworkLoads;
}
-
-
+
+
private void verifyNetworkAccess() {
if (!mBlockNetworkLoads) {
if (mContext.checkPermission("android.permission.INTERNET",
@@ -886,19 +893,94 @@ public class WebSettings {
}
/**
- * Set a custom path to plugins used by the WebView. The client
- * must ensure it exists before this call.
- * @param pluginsPath String path to the directory containing plugins.
+ * TODO: need to add @Deprecated
*/
public synchronized void setPluginsPath(String pluginsPath) {
- if (pluginsPath != null && !pluginsPath.equals(mPluginsPath)) {
- mPluginsPath = pluginsPath;
+ }
+
+ /**
+ * @hide
+ * Set the default quota for WebStorage DBs
+ * @param quota the default quota in bytes
+ */
+ public synchronized void setWebStorageDefaultQuota(long quota) {
+ if (mWebStorageDefaultQuota != quota) {
+ mWebStorageDefaultQuota = quota;
+ postSync();
+ }
+ }
+
+ /**
+ * Set the path to where database storage API databases should be saved.
+ * This will update WebCore when the Sync runs in the C++ side.
+ * @param databasePath String path to the directory where databases should
+ * be saved. May be the empty string but should never be null.
+ */
+ public synchronized void setDatabasePath(String databasePath) {
+ if (databasePath != null && !databasePath.equals(mDatabasePath)) {
+ mDatabasePath = databasePath;
+ postSync();
+ }
+ }
+
+ /**
+ * Tell the WebView to enable Application Caches API.
+ * @param flag True if the WebView should enable Application Caches.
+ * @hide pending api council approval
+ */
+ public synchronized void setAppCacheEnabled(boolean flag) {
+ if (mAppCacheEnabled != flag) {
+ mAppCacheEnabled = flag;
+ postSync();
+ }
+ }
+
+ /**
+ * Set a custom path to the Application Caches files. The client
+ * must ensure it exists before this call.
+ * @param appCachePath String path to the directory containing Application
+ * Caches files. The appCache path can be the empty string but should not
+ * be null. Passing null for this parameter will result in a no-op.
+ * @hide pending api council approval
+ */
+ public synchronized void setAppCachePath(String appCachePath) {
+ if (appCachePath != null && !appCachePath.equals(mAppCachePath)) {
+ mAppCachePath = appCachePath;
postSync();
}
}
/**
- * Return true if javascript is enabled.
+ * Set whether the database storage API is enabled.
+ * @param flag boolean True if the WebView should use the database storage
+ * API.
+ */
+ public synchronized void setDatabaseEnabled(boolean flag) {
+ if (mDatabaseEnabled != flag) {
+ mDatabaseEnabled = flag;
+ postSync();
+ }
+ }
+
+ /**
+ * Return the path to where database storage API databases are saved for
+ * the current WebView.
+ * @return the String path to the database storage API databases.
+ */
+ public synchronized String getDatabasePath() {
+ return mDatabasePath;
+ }
+
+ /**
+ * Returns true if database storage API is enabled.
+ * @return True if the database storage API is enabled.
+ */
+ public synchronized boolean getDatabaseEnabled() {
+ return mDatabaseEnabled;
+ }
+
+ /**
+ * Return true if javascript is enabled. <b>Note: The default is false.</b>
* @return True if javascript is enabled.
*/
public synchronized boolean getJavaScriptEnabled() {
@@ -914,11 +996,19 @@ public class WebSettings {
}
/**
- * Return the current path used for plugins in the WebView.
- * @return The string path to the WebView plugins.
+ * TODO: need to add @Deprecated
*/
public synchronized String getPluginsPath() {
- return mPluginsPath;
+ return "";
+ }
+
+ /**
+ * @hide
+ * Return the default quota for WebStorage DBs
+ * @return the default quota in bytes
+ */
+ public synchronized long getWebStorageDefaultQuota() {
+ return mWebStorageDefaultQuota;
}
/**
@@ -935,7 +1025,8 @@ public class WebSettings {
}
/**
- * Return true if javascript can open windows automatically.
+ * Return true if javascript can open windows automatically. The default
+ * is false.
* @return True if javascript can open windows automatically during
* window.open().
*/
@@ -955,7 +1046,7 @@ public class WebSettings {
}
/**
- * Get the default text encoding name.
+ * Get the default text encoding name. The default is "Latin-1".
* @return The default text encoding name as a string.
*/
public synchronized String getDefaultTextEncodingName() {
@@ -1044,8 +1135,8 @@ public class WebSettings {
/**
* Set the priority of the Render thread. Unlike the other settings, this
- * one only needs to be called once per process.
- *
+ * one only needs to be called once per process. The default is NORMAL.
+ *
* @param priority RenderPriority, can be normal, high or low.
*/
public synchronized void setRenderPriority(RenderPriority priority) {
@@ -1099,7 +1190,7 @@ public class WebSettings {
/*package*/
synchronized void syncSettingsAndCreateHandler(BrowserFrame frame) {
mBrowserFrame = frame;
- if (WebView.DEBUG) {
+ if (DebugFlags.WEB_SETTINGS) {
junit.framework.Assert.assertTrue(frame.mNativeFrame != 0);
}
nativeSync(frame.mNativeFrame);
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
new file mode 100644
index 0000000..f27360d
--- /dev/null
+++ b/core/java/android/webkit/WebStorage.java
@@ -0,0 +1,283 @@
+/*
+ * 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.webkit;
+
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.HashMap;
+import java.util.Vector;
+
+/**
+ * Functionality for manipulating the webstorage databases.
+ */
+public final class WebStorage {
+
+ /**
+ * Encapsulates a callback function to be executed when a new quota is made
+ * available. We primarily want this to allow us to call back the sleeping
+ * WebCore thread from outside the WebViewCore class (as the native call
+ * is private). It is imperative that this the setDatabaseQuota method is
+ * executed once a decision to either allow or deny new quota is made,
+ * otherwise the WebCore thread will remain asleep.
+ */
+ public interface QuotaUpdater {
+ public void updateQuota(long newQuota);
+ };
+
+ // Log tag
+ private static final String TAG = "webstorage";
+
+ // Global instance of a WebStorage
+ private static WebStorage sWebStorage;
+
+ // We keep a copy of the origins, quotas and usages
+ // that we protect via a lock and update in syncValues()
+ private static Lock mLock = new ReentrantLock();
+ private static Condition mCacheUpdated = mLock.newCondition();
+
+ // Message ids
+ static final int UPDATE = 0;
+ static final int SET_QUOTA_ORIGIN = 1;
+ static final int DELETE_ORIGIN = 2;
+ static final int DELETE_ALL = 3;
+
+ private Vector <String> mOrigins;
+ private HashMap <String, Long> mQuotas = new HashMap<String, Long>();
+ private HashMap <String, Long> mUsages = new HashMap<String, Long>();
+
+ private Handler mHandler = null;
+
+ private class Origin {
+ String mOrigin = null;
+ long mQuota = 0;
+
+ public Origin(String origin, long quota) {
+ mOrigin = origin;
+ mQuota = quota;
+ }
+
+ public Origin(String origin) {
+ mOrigin = origin;
+ }
+
+ public String getOrigin() {
+ return mOrigin;
+ }
+
+ public long getQuota() {
+ return mQuota;
+ }
+ }
+
+ /**
+ * @hide
+ * Message handler
+ */
+ public void createHandler() {
+ if (mHandler == null) {
+ mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case SET_QUOTA_ORIGIN: {
+ Origin website = (Origin) msg.obj;
+ nativeSetQuotaForOrigin(website.getOrigin(),
+ website.getQuota());
+ syncValues();
+ } break;
+
+ case DELETE_ORIGIN: {
+ Origin website = (Origin) msg.obj;
+ nativeDeleteOrigin(website.getOrigin());
+ syncValues();
+ } break;
+
+ case DELETE_ALL:
+ nativeDeleteAllDatabases();
+ syncValues();
+ break;
+
+ case UPDATE:
+ syncValues();
+ break;
+ }
+ }
+ };
+ }
+ }
+
+ /**
+ * @hide
+ * Returns a list of origins having a database
+ */
+ public Vector getOrigins() {
+ Vector ret = null;
+ mLock.lock();
+ try {
+ update();
+ mCacheUpdated.await();
+ ret = mOrigins;
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Exception while waiting on the updated origins", e);
+ } finally {
+ mLock.unlock();
+ }
+ return ret;
+ }
+
+ /**
+ * @hide
+ * Returns the use for a given origin
+ */
+ public long getUsageForOrigin(String origin) {
+ long ret = 0;
+ if (origin == null) {
+ return ret;
+ }
+ mLock.lock();
+ try {
+ update();
+ mCacheUpdated.await();
+ Long usage = mUsages.get(origin);
+ if (usage != null) {
+ ret = usage.longValue();
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Exception while waiting on the updated origins", e);
+ } finally {
+ mLock.unlock();
+ }
+ return ret;
+ }
+
+ /**
+ * @hide
+ * Returns the quota for a given origin
+ */
+ public long getQuotaForOrigin(String origin) {
+ long ret = 0;
+ if (origin == null) {
+ return ret;
+ }
+ mLock.lock();
+ try {
+ update();
+ mCacheUpdated.await();
+ Long quota = mQuotas.get(origin);
+ if (quota != null) {
+ ret = quota.longValue();
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Exception while waiting on the updated origins", e);
+ } finally {
+ mLock.unlock();
+ }
+ return ret;
+ }
+
+ /**
+ * @hide
+ * Set the quota for a given origin
+ */
+ public void setQuotaForOrigin(String origin, long quota) {
+ if (origin != null) {
+ postMessage(Message.obtain(null, SET_QUOTA_ORIGIN,
+ new Origin(origin, quota)));
+ }
+ }
+
+ /**
+ * @hide
+ * Delete a given origin
+ */
+ public void deleteOrigin(String origin) {
+ if (origin != null) {
+ postMessage(Message.obtain(null, DELETE_ORIGIN,
+ new Origin(origin)));
+ }
+ }
+
+ /**
+ * @hide
+ * Delete all databases
+ */
+ public void deleteAllDatabases() {
+ postMessage(Message.obtain(null, DELETE_ALL));
+ }
+
+ /**
+ * Utility function to send a message to our handler
+ */
+ private void postMessage(Message msg) {
+ if (mHandler != null) {
+ mHandler.sendMessage(msg);
+ }
+ }
+
+ /**
+ * @hide
+ * Get the global instance of WebStorage.
+ * @return A single instance of WebStorage.
+ */
+ public static WebStorage getInstance() {
+ if (sWebStorage == null) {
+ sWebStorage = new WebStorage();
+ }
+ return sWebStorage;
+ }
+
+ /**
+ * @hide
+ * Post a Sync request
+ */
+ public void update() {
+ postMessage(Message.obtain(null, UPDATE));
+ }
+
+ /**
+ * Run on the webcore thread
+ * sync the local cached values with the real ones
+ */
+ private void syncValues() {
+ mLock.lock();
+ Vector tmp = nativeGetOrigins();
+ mOrigins = new Vector<String>();
+ mQuotas.clear();
+ mUsages.clear();
+ for (int i = 0; i < tmp.size(); i++) {
+ String origin = (String) tmp.get(i);
+ mOrigins.add(origin);
+ mQuotas.put(origin, new Long(nativeGetQuotaForOrigin(origin)));
+ mUsages.put(origin, new Long(nativeGetUsageForOrigin(origin)));
+ }
+ mCacheUpdated.signal();
+ mLock.unlock();
+ }
+
+ // Native functions
+ private static native Vector nativeGetOrigins();
+ private static native long nativeGetUsageForOrigin(String origin);
+ private static native long nativeGetQuotaForOrigin(String origin);
+ private static native void nativeSetQuotaForOrigin(String origin, long quota);
+ private static native void nativeDeleteOrigin(String origin);
+ private static native void nativeDeleteAllDatabases();
+}
diff --git a/core/java/android/webkit/WebSyncManager.java b/core/java/android/webkit/WebSyncManager.java
index ded17ed..d3ec603 100644
--- a/core/java/android/webkit/WebSyncManager.java
+++ b/core/java/android/webkit/WebSyncManager.java
@@ -47,7 +47,7 @@ abstract class WebSyncManager implements Runnable {
@Override
public void handleMessage(Message msg) {
if (msg.what == SYNC_MESSAGE) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.WEB_SYNC_MANAGER) {
Log.v(LOGTAG, "*** WebSyncManager sync ***");
}
syncFromRamToFlash();
@@ -94,7 +94,7 @@ abstract class WebSyncManager implements Runnable {
* sync() forces sync manager to sync now
*/
public void sync() {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.WEB_SYNC_MANAGER) {
Log.v(LOGTAG, "*** WebSyncManager sync ***");
}
if (mHandler == null) {
@@ -109,7 +109,7 @@ abstract class WebSyncManager implements Runnable {
* resetSync() resets sync manager's timer
*/
public void resetSync() {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.WEB_SYNC_MANAGER) {
Log.v(LOGTAG, "*** WebSyncManager resetSync ***");
}
if (mHandler == null) {
@@ -124,7 +124,7 @@ abstract class WebSyncManager implements Runnable {
* startSync() requests sync manager to start sync
*/
public void startSync() {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.WEB_SYNC_MANAGER) {
Log.v(LOGTAG, "*** WebSyncManager startSync ***, Ref count:" +
mStartSyncRefCount);
}
@@ -142,7 +142,7 @@ abstract class WebSyncManager implements Runnable {
* the queue to break the sync loop
*/
public void stopSync() {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.WEB_SYNC_MANAGER) {
Log.v(LOGTAG, "*** WebSyncManager stopSync ***, Ref count:" +
mStartSyncRefCount);
}
diff --git a/core/java/android/webkit/TextDialog.java b/core/java/android/webkit/WebTextView.java
index 99de56d..4a8fa3c 100644
--- a/core/java/android/webkit/TextDialog.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -17,19 +17,11 @@
package android.webkit;
import android.content.Context;
-import android.graphics.Color;
-import android.graphics.Paint;
import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.RectShape;
import android.text.Editable;
import android.text.InputFilter;
import android.text.Selection;
import android.text.Spannable;
-import android.text.TextPaint;
import android.text.TextUtils;
import android.text.method.MovementMethod;
import android.view.inputmethod.EditorInfo;
@@ -47,11 +39,11 @@ import android.widget.TextView;
import java.util.ArrayList;
/**
- * TextDialog is a specialized version of EditText used by WebView
+ * WebTextView is a specialized version of EditText used by WebView
* to overlay html textfields (and textareas) to use our standard
* text editing.
*/
-/* package */ class TextDialog extends AutoCompleteTextView {
+/* package */ class WebTextView extends AutoCompleteTextView {
private WebView mWebView;
private boolean mSingle;
@@ -79,39 +71,17 @@ import java.util.ArrayList;
private static final InputFilter[] NO_FILTERS = new InputFilter[0];
/**
- * Create a new TextDialog.
- * @param context The Context for this TextDialog.
+ * Create a new WebTextView.
+ * @param context The Context for this WebTextView.
* @param webView The WebView that created this.
*/
- /* package */ TextDialog(Context context, WebView webView) {
+ /* package */ WebTextView(Context context, WebView webView) {
super(context);
mWebView = webView;
- ShapeDrawable background = new ShapeDrawable(new RectShape());
- Paint shapePaint = background.getPaint();
- shapePaint.setStyle(Paint.Style.STROKE);
- ColorDrawable color = new ColorDrawable(Color.WHITE);
- Drawable[] array = new Drawable[2];
- array[0] = color;
- array[1] = background;
- LayerDrawable layers = new LayerDrawable(array);
- // Hide WebCore's text behind this and allow the WebView
- // to draw its own focusring.
- setBackgroundDrawable(layers);
- // Align the text better with the text behind it, so moving
- // off of the textfield will not appear to move the text.
- setPadding(3, 2, 0, 0);
mMaxLength = -1;
- // Turn on subpixel text, and turn off kerning, so it better matches
- // the text in webkit.
- TextPaint paint = getPaint();
- int flags = paint.getFlags() | Paint.SUBPIXEL_TEXT_FLAG |
- Paint.ANTI_ALIAS_FLAG & ~Paint.DEV_KERN_TEXT_FLAG;
- paint.setFlags(flags);
- // Set the text color to black, regardless of the theme. This ensures
- // that other applications that use embedded WebViews will properly
- // display the text in textfields.
- setTextColor(Color.BLACK);
setImeOptions(EditorInfo.IME_ACTION_NONE);
+ // Allow webkit's drawing to show through
+ setWillNotDraw(true);
}
@Override
@@ -125,7 +95,7 @@ import java.util.ArrayList;
Spannable text = (Spannable) getText();
int oldLength = text.length();
// Normally the delete key's dom events are sent via onTextChanged.
- // However, if the length is zero, the text did not change, so we
+ // However, if the length is zero, the text did not change, so we
// go ahead and pass the key down immediately.
if (KeyEvent.KEYCODE_DEL == keyCode && 0 == oldLength) {
sendDomEvent(event);
@@ -151,6 +121,10 @@ import java.util.ArrayList;
if (isPopupShowing()) {
return super.dispatchKeyEvent(event);
}
+ if (!mWebView.nativeCursorMatchesFocus()) {
+ return down ? mWebView.onKeyDown(keyCode, event) : mWebView
+ .onKeyUp(keyCode, event);
+ }
// Center key should be passed to a potential onClick
if (!down) {
mWebView.shortPressOnTextField();
@@ -158,6 +132,20 @@ import java.util.ArrayList;
// Pass to super to handle longpress.
return super.dispatchKeyEvent(event);
}
+ boolean isArrowKey = false;
+ switch(keyCode) {
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ case KeyEvent.KEYCODE_DPAD_UP:
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ if (!mWebView.nativeCursorMatchesFocus()) {
+ return down ? mWebView.onKeyDown(keyCode, event) : mWebView
+ .onKeyUp(keyCode, event);
+
+ }
+ isArrowKey = true;
+ break;
+ }
// Ensure there is a layout so arrow keys are handled properly.
if (getLayout() == null) {
@@ -177,7 +165,7 @@ import java.util.ArrayList;
oldText = "";
}
if (super.dispatchKeyEvent(event)) {
- // If the TextDialog handled the key it was either an alphanumeric
+ // If the WebTextView handled the key it was either an alphanumeric
// key, a delete, or a movement within the text. All of those are
// ok to pass to javascript.
@@ -187,22 +175,11 @@ import java.util.ArrayList;
// so do not pass down to javascript, and instead
// return true. If it is an arrow key or a delete key, we can go
// ahead and pass it down.
- boolean isArrowKey;
- switch(keyCode) {
- case KeyEvent.KEYCODE_DPAD_LEFT:
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- case KeyEvent.KEYCODE_DPAD_UP:
- case KeyEvent.KEYCODE_DPAD_DOWN:
- isArrowKey = true;
- break;
- case KeyEvent.KEYCODE_ENTER:
- // For multi-line text boxes, newlines will
- // trigger onTextChanged for key down (which will send both
- // key up and key down) but not key up.
- mGotEnterDown = true;
- default:
- isArrowKey = false;
- break;
+ if (KeyEvent.KEYCODE_ENTER == keyCode) {
+ // For multi-line text boxes, newlines will
+ // trigger onTextChanged for key down (which will send both
+ // key up and key down) but not key up.
+ mGotEnterDown = true;
}
if (maxedOut && !isArrowKey && keyCode != KeyEvent.KEYCODE_DEL) {
if (oldEnd == oldStart) {
@@ -225,32 +202,31 @@ import java.util.ArrayList;
return true;
}
}
+ /* FIXME:
+ * In theory, we would like to send the events for the arrow keys.
+ * However, the TextView can arbitrarily change the selection (i.e.
+ * long press followed by using the trackball). Therefore, we keep
+ * in sync with the TextView via onSelectionChanged. If we also
+ * send the DOM event, we lose the correct selection.
if (isArrowKey) {
// Arrow key does not change the text, but we still want to send
// the DOM events.
sendDomEvent(event);
}
+ */
mScrollToAccommodateCursor = true;
return true;
}
- // FIXME: TextViews return false for up and down key events even though
- // they change the selection. Since we don't want the get out of sync
- // with WebCore's notion of the current selection, reset the selection
- // to what it was before the key event.
- Selection.setSelection(text, oldStart, oldEnd);
// Ignore the key up event for newlines. This prevents
// multiple newlines in the native textarea.
if (mGotEnterDown && !down) {
return true;
}
// if it is a navigation key, pass it to WebView
- if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT
- || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT
- || keyCode == KeyEvent.KEYCODE_DPAD_UP
- || keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
+ if (isArrowKey) {
// WebView check the trackballtime in onKeyDown to avoid calling
- // native from both trackball and key handling. As this is called
- // from TextDialog, we always want WebView to check with native.
+ // native from both trackball and key handling. As this is called
+ // from WebTextView, we always want WebView to check with native.
// Reset trackballtime to ensure it.
mWebView.resetTrackballTime();
return down ? mWebView.onKeyDown(keyCode, event) : mWebView
@@ -260,9 +236,9 @@ import java.util.ArrayList;
}
/**
- * Create a fake touch up event at (x,y) with respect to this TextDialog.
+ * Create a fake touch up event at (x,y) with respect to this WebTextView.
* This is used by WebView to act as though a touch event which happened
- * before we placed the TextDialog actually hit it, so that it can place
+ * before we placed the WebTextView actually hit it, so that it can place
* the cursor accordingly.
*/
/* package */ void fakeTouchEvent(float x, float y) {
@@ -279,10 +255,10 @@ import java.util.ArrayList;
}
/**
- * Determine whether this TextDialog currently represents the node
+ * Determine whether this WebTextView currently represents the node
* represented by ptr.
* @param ptr Pointer to a node to compare to.
- * @return boolean Whether this TextDialog already represents the node
+ * @return boolean Whether this WebTextView already represents the node
* pointed to by ptr.
*/
/* package */ boolean isSameTextField(int ptr) {
@@ -290,20 +266,19 @@ import java.util.ArrayList;
}
@Override
- public boolean onPreDraw() {
- if (getLayout() == null) {
- measure(mWidthSpec, mHeightSpec);
+ protected void onSelectionChanged(int selStart, int selEnd) {
+ if (mWebView != null) {
+ mWebView.setSelection(selStart, selEnd);
}
- return super.onPreDraw();
}
-
+
@Override
protected void onTextChanged(CharSequence s,int start,int before,int count){
super.onTextChanged(s, start, before, count);
String postChange = s.toString();
// Prevent calls to setText from invoking onTextChanged (since this will
// mean we are on a different textfield). Also prevent the change when
- // going from a textfield with a string of text to one with a smaller
+ // going from a textfield with a string of text to one with a smaller
// limit on text length from registering the onTextChanged event.
if (mPreChange == null || mPreChange.equals(postChange) ||
(mMaxLength > -1 && mPreChange.length() > mMaxLength &&
@@ -311,8 +286,7 @@ import java.util.ArrayList;
return;
}
mPreChange = postChange;
- // This was simply a delete or a cut, so just delete the
- // selection.
+ // This was simply a delete or a cut, so just delete the selection.
if (before > 0 && 0 == count) {
mWebView.deleteSelection(start, start + before);
// For this and all changes to the text, update our cache
@@ -337,24 +311,23 @@ import java.util.ArrayList;
start + count - charactersFromKeyEvents,
start + count - charactersFromKeyEvents);
} else {
- // This corrects the selection which may have been affected by the
+ // This corrects the selection which may have been affected by the
// trackball or auto-correct.
mWebView.setSelection(start, start + before);
}
- updateCachedTextfield();
- if (cannotUseKeyEvents) {
- return;
- }
- int length = events.length;
- for (int i = 0; i < length; i++) {
- // We never send modifier keys to native code so don't send them
- // here either.
- if (!KeyEvent.isModifierKey(events[i].getKeyCode())) {
- sendDomEvent(events[i]);
+ if (!cannotUseKeyEvents) {
+ int length = events.length;
+ for (int i = 0; i < length; i++) {
+ // We never send modifier keys to native code so don't send them
+ // here either.
+ if (!KeyEvent.isModifierKey(events[i].getKeyCode())) {
+ sendDomEvent(events[i]);
+ }
}
}
+ updateCachedTextfield();
}
-
+
@Override
public boolean onTrackballEvent(MotionEvent event) {
if (isPopupShowing()) {
@@ -363,16 +336,16 @@ import java.util.ArrayList;
if (event.getAction() != MotionEvent.ACTION_MOVE) {
return false;
}
+ // If the Cursor is not on the text input, webview should handle the
+ // trackball
+ if (!mWebView.nativeCursorMatchesFocus()) {
+ return mWebView.onTrackballEvent(event);
+ }
Spannable text = (Spannable) getText();
MovementMethod move = getMovementMethod();
if (move != null && getLayout() != null &&
move.onTrackballEvent(this, text, event)) {
- // Need to pass down the selection, which has changed.
- // FIXME: This should work, but does not, so we set the selection
- // in onTextChanged.
- //int start = Selection.getSelectionStart(text);
- //int end = Selection.getSelectionEnd(text);
- //mWebView.setSelection(start, end);
+ // Selection is changed in onSelectionChanged
return true;
}
// If the user is in a textfield, and the movement method is not
@@ -385,7 +358,7 @@ import java.util.ArrayList;
}
/**
- * Remove this TextDialog from its host WebView, and return
+ * Remove this WebTextView from its host WebView, and return
* focus to the host.
*/
/* package */ void remove() {
@@ -414,7 +387,7 @@ import java.util.ArrayList;
}
return false;
}
-
+
/**
* Send the DOM events for the specified event.
* @param event KeyEvent to be translated into a DOM event.
@@ -425,7 +398,7 @@ import java.util.ArrayList;
/**
* Always use this instead of setAdapter, as this has features specific to
- * the TextDialog.
+ * the WebTextView.
*/
public void setAdapterCustom(AutoCompleteAdapter adapter) {
if (adapter != null) {
@@ -491,16 +464,16 @@ import java.util.ArrayList;
/**
* Set the pointer for this node so it can be determined which node this
- * TextDialog represents.
+ * WebTextView represents.
* @param ptr Integer representing the pointer to the node which this
- * TextDialog represents.
+ * WebTextView represents.
*/
/* package */ void setNodePointer(int ptr) {
mNodePointer = ptr;
}
/**
- * Determine the position and size of TextDialog, and add it to the
+ * Determine the position and size of WebTextView, and add it to the
* WebView's view heirarchy. All parameters are presumed to be in
* view coordinates. Also requests Focus and sets the cursor to not
* request to be in view.
@@ -551,8 +524,8 @@ import java.util.ArrayList;
}
/**
- * Set the text for this TextDialog, and set the selection to (start, end)
- * @param text Text to go into this TextDialog.
+ * Set the text for this WebTextView, and set the selection to (start, end)
+ * @param text Text to go into this WebTextView.
* @param start Beginning of the selection.
* @param end End of the selection.
*/
@@ -583,7 +556,7 @@ import java.util.ArrayList;
edit.replace(0, edit.length(), text);
updateCachedTextfield();
}
-
+
/**
* Update the cache to reflect the current text.
*/
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 563d819..2940983 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -58,7 +58,7 @@ import android.view.ViewParent;
import android.view.ViewTreeObserver;
import android.view.animation.AlphaAnimation;
import android.view.inputmethod.InputMethodManager;
-import android.webkit.TextDialog.AutoCompleteAdapter;
+import android.webkit.WebTextView.AutoCompleteAdapter;
import android.webkit.WebViewCore.EventHub;
import android.widget.AbsoluteLayout;
import android.widget.Adapter;
@@ -84,7 +84,7 @@ import java.util.HashMap;
import java.util.List;
/**
- * <p>A View that displays web pages. This class is the basis upon which you
+ * <p>A View that displays web pages. This class is the basis upon which you
* can roll your own web browser or simply display some online content within your Activity.
* It uses the WebKit rendering engine to display
* web pages and includes methods to navigate forward and backward
@@ -93,12 +93,109 @@ import java.util.List;
* {@link #getSettings() WebSettings}.{@link WebSettings#setBuiltInZoomControls(boolean)}
* (introduced in API version 3).
* <p>Note that, in order for your Activity to access the Internet and load web pages
- * in a WebView, you must add the <var>INTERNET</var> permissions to your
+ * in a WebView, you must add the <var>INTERNET</var> permissions to your
* Android Manifest file:</p>
* <pre>&lt;uses-permission android:name="android.permission.INTERNET" /></pre>
+ *
* <p>This must be a child of the <code>&lt;manifest></code> element.</p>
+ *
+ * <h3>Basic usage</h3>
+ *
+ * <p>By default, a WebView provides no browser-like widgets, does not
+ * enable JavaScript and errors will be ignored. If your goal is only
+ * to display some HTML as a part of your UI, this is probably fine;
+ * the user won't need to interact with the web page beyond reading
+ * it, and the web page won't need to interact with the user. If you
+ * actually want a fully blown web browser, then you probably want to
+ * invoke the Browser application with your URL rather than show it
+ * with a WebView. See {@link android.content.Intent} for more information.</p>
+ *
+ * <pre class="prettyprint">
+ * WebView webview = new WebView(this);
+ * setContentView(webview);
+ *
+ * // Simplest usage: note that an exception will NOT be thrown
+ * // if there is an error loading this page (see below).
+ * webview.loadUrl("http://slashdot.org/");
+ *
+ * // Of course you can also load from any string:
+ * String summary = "&lt;html>&lt;body>You scored &lt;b>192</b> points.&lt;/body>&lt;/html>";
+ * webview.loadData(summary, "text/html", "utf-8");
+ * // ... although note that there are restrictions on what this HTML can do.
+ * // See the JavaDocs for loadData and loadDataWithBaseUrl for more info.
+ * </pre>
+ *
+ * <p>A WebView has several customization points where you can add your
+ * own behavior. These are:</p>
+ *
+ * <ul>
+ * <li>Creating and setting a {@link android.webkit.WebChromeClient} subclass.
+ * This class is called when something that might impact a
+ * browser UI happens, for instance, progress updates and
+ * JavaScript alerts are sent here.
+ * </li>
+ * <li>Creating and setting a {@link android.webkit.WebViewClient} subclass.
+ * It will be called when things happen that impact the
+ * rendering of the content, eg, errors or form submissions. You
+ * can also intercept URL loading here.</li>
+ * <li>Via the {@link android.webkit.WebSettings} class, which contains
+ * miscellaneous configuration. </li>
+ * <li>With the {@link android.webkit.WebView#addJavascriptInterface} method.
+ * This lets you bind Java objects into the WebView so they can be
+ * controlled from the web pages JavaScript.</li>
+ * </ul>
+ *
+ * <p>Here's a more complicated example, showing error handling,
+ * settings, and progress notification:</p>
+ *
+ * <pre class="prettyprint">
+ * // Let's display the progress in the activity title bar, like the
+ * // browser app does.
+ * getWindow().requestFeature(Window.FEATURE_PROGRESS);
+ *
+ * webview.getSettings().setJavaScriptEnabled(true);
+ *
+ * final Activity activity = this;
+ * webview.setWebChromeClient(new WebChromeClient() {
+ * public void onProgressChanged(WebView view, int progress) {
+ * // Activities and WebViews measure progress with different scales.
+ * // The progress meter will automatically disappear when we reach 100%
+ * activity.setProgress(progress * 1000);
+ * }
+ * });
+ * webview.setWebViewClient(new WebViewClient() {
+ * public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
+ * Toast.makeText(activity, "Oh no! " + description, Toast.LENGTH_SHORT).show();
+ * }
+ * });
+ *
+ * webview.loadUrl("http://slashdot.org/");
+ * </pre>
+ *
+ * <h3>Cookie and window management</h3>
+ *
+ * <p>For obvious security reasons, your application has its own
+ * cache, cookie store etc - it does not share the Browser
+ * applications data. Cookies are managed on a separate thread, so
+ * operations like index building don't block the UI
+ * thread. Follow the instructions in {@link android.webkit.CookieSyncManager}
+ * if you want to use cookies in your application.
+ * </p>
+ *
+ * <p>By default, requests by the HTML to open new windows are
+ * ignored. This is true whether they be opened by JavaScript or by
+ * the target attribute on a link. You can customize your
+ * WebChromeClient to provide your own behaviour for opening multiple windows,
+ * and render them in whatever manner you want.</p>
+ *
+ * <p>Standard behavior for an Activity is to be destroyed and
+ * recreated when the devices orientation is changed. This will cause
+ * the WebView to reload the current page. If you don't want that, you
+ * can set your Activity to handle the orientation and keyboardHidden
+ * changes, and then just leave the WebView alone. It'll automatically
+ * re-orient itself as appropriate.</p>
*/
-public class WebView extends AbsoluteLayout
+public class WebView extends AbsoluteLayout
implements ViewTreeObserver.OnGlobalFocusChangeListener,
ViewGroup.OnHierarchyChangeListener {
@@ -108,12 +205,9 @@ public class WebView extends AbsoluteLayout
// true means redraw the screen all-the-time. Only with AUTO_REDRAW_HACK
private boolean mAutoRedraw;
- // keep debugging parameters near the top of the file
static final String LOGTAG = "webview";
- static final boolean DEBUG = false;
- static final boolean LOGV_ENABLED = DEBUG;
- private class ExtendedZoomControls extends FrameLayout {
+ private static class ExtendedZoomControls extends FrameLayout {
public ExtendedZoomControls(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = (LayoutInflater)
@@ -122,40 +216,40 @@ public class WebView extends AbsoluteLayout
mZoomControls = (ZoomControls) findViewById(com.android.internal.R.id.zoomControls);
mZoomMagnify = (ImageView) findViewById(com.android.internal.R.id.zoomMagnify);
}
-
+
public void show(boolean showZoom, boolean canZoomOut) {
mZoomControls.setVisibility(showZoom ? View.VISIBLE : View.GONE);
mZoomMagnify.setVisibility(canZoomOut ? View.VISIBLE : View.GONE);
fade(View.VISIBLE, 0.0f, 1.0f);
}
-
+
public void hide() {
fade(View.GONE, 1.0f, 0.0f);
}
-
+
private void fade(int visibility, float startAlpha, float endAlpha) {
AlphaAnimation anim = new AlphaAnimation(startAlpha, endAlpha);
anim.setDuration(500);
startAnimation(anim);
setVisibility(visibility);
}
-
+
public void setIsZoomMagnifyEnabled(boolean isEnabled) {
mZoomMagnify.setEnabled(isEnabled);
}
-
+
public boolean hasFocus() {
return mZoomControls.hasFocus() || mZoomMagnify.hasFocus();
}
-
+
public void setOnZoomInClickListener(OnClickListener listener) {
mZoomControls.setOnZoomInClickListener(listener);
}
-
+
public void setOnZoomOutClickListener(OnClickListener listener) {
mZoomControls.setOnZoomOutClickListener(listener);
}
-
+
public void setOnZoomMagnifyClickListener(OnClickListener listener) {
mZoomMagnify.setOnClickListener(listener);
}
@@ -163,7 +257,7 @@ public class WebView extends AbsoluteLayout
ZoomControls mZoomControls;
ImageView mZoomMagnify;
}
-
+
/**
* Transportation object for returning WebView across thread boundaries.
*/
@@ -203,7 +297,7 @@ public class WebView extends AbsoluteLayout
private WebViewCore mWebViewCore;
// Handler for dispatching UI messages.
/* package */ final Handler mPrivateHandler = new PrivateHandler();
- private TextDialog mTextEntry;
+ private WebTextView mWebTextView;
// Used to ignore changes to webkit text that arrives to the UI side after
// more key events.
private int mTextGeneration;
@@ -266,12 +360,15 @@ public class WebView extends AbsoluteLayout
// take control of touch events unless it says no for touch down event.
private boolean mPreventDrag;
- // If updateTextEntry gets called while we are out of focus, use this
+ // If rebuildWebTextView gets called while we are out of focus, use this
// variable to remember to do it next time we gain focus.
- private boolean mNeedsUpdateTextEntry = false;
-
- // Whether or not to draw the focus ring.
- private boolean mDrawFocusRing = true;
+ private boolean mNeedsRebuildWebTextView = false;
+
+ // Whether or not to draw the cursor ring.
+ private boolean mDrawCursorRing = true;
+
+ // true if onPause has been called (and not onResume)
+ private boolean mIsPaused;
/**
* Customizable constant
@@ -291,7 +388,7 @@ public class WebView extends AbsoluteLayout
// needed to avoid flinging after a pause of no movement
private static final int MIN_FLING_TIME = 250;
// The time that the Zoom Controls are visible before fading away
- private static final long ZOOM_CONTROLS_TIMEOUT =
+ private static final long ZOOM_CONTROLS_TIMEOUT =
ViewConfiguration.getZoomControlsTimeout();
// The amount of content to overlap between two screens when going through
// pages with the space bar, in pixels.
@@ -312,7 +409,7 @@ public class WebView extends AbsoluteLayout
private int mContentWidth; // cache of value from WebViewCore
private int mContentHeight; // cache of value from WebViewCore
- // Need to have the separate control for horizontal and vertical scrollbar
+ // Need to have the separate control for horizontal and vertical scrollbar
// style than the View's single scrollbar style
private boolean mOverlayHorizontalScrollbar = true;
private boolean mOverlayVerticalScrollbar = false;
@@ -327,51 +424,48 @@ public class WebView extends AbsoluteLayout
private boolean mWrapContent;
- // true if we should call webcore to draw the content, false means we have
- // requested something but it isn't ready to draw yet.
- private WebViewCore.FocusData mFocusData;
/**
* Private message ids
*/
- private static final int REMEMBER_PASSWORD = 1;
- private static final int NEVER_REMEMBER_PASSWORD = 2;
- private static final int SWITCH_TO_SHORTPRESS = 3;
- private static final int SWITCH_TO_LONGPRESS = 4;
- private static final int UPDATE_TEXT_ENTRY_ADAPTER = 6;
- private static final int SWITCH_TO_ENTER = 7;
- private static final int RESUME_WEBCORE_UPDATE = 8;
+ private static final int REMEMBER_PASSWORD = 1;
+ private static final int NEVER_REMEMBER_PASSWORD = 2;
+ private static final int SWITCH_TO_SHORTPRESS = 3;
+ private static final int SWITCH_TO_LONGPRESS = 4;
+ private static final int REQUEST_FORM_DATA = 6;
+ private static final int SWITCH_TO_CLICK = 7;
+ private static final int RESUME_WEBCORE_UPDATE = 8;
//! arg1=x, arg2=y
- static final int SCROLL_TO_MSG_ID = 10;
- static final int SCROLL_BY_MSG_ID = 11;
+ static final int SCROLL_TO_MSG_ID = 10;
+ static final int SCROLL_BY_MSG_ID = 11;
//! arg1=x, arg2=y
- static final int SPAWN_SCROLL_TO_MSG_ID = 12;
+ static final int SPAWN_SCROLL_TO_MSG_ID = 12;
//! arg1=x, arg2=y
- static final int SYNC_SCROLL_TO_MSG_ID = 13;
- static final int NEW_PICTURE_MSG_ID = 14;
- static final int UPDATE_TEXT_ENTRY_MSG_ID = 15;
- static final int WEBCORE_INITIALIZED_MSG_ID = 16;
- static final int UPDATE_TEXTFIELD_TEXT_MSG_ID = 17;
- static final int DID_FIRST_LAYOUT_MSG_ID = 18;
- static final int RECOMPUTE_FOCUS_MSG_ID = 19;
- static final int NOTIFY_FOCUS_SET_MSG_ID = 20;
- static final int MARK_NODE_INVALID_ID = 21;
- static final int UPDATE_CLIPBOARD = 22;
- static final int LONG_PRESS_ENTER = 23;
- static final int PREVENT_TOUCH_ID = 24;
- static final int WEBCORE_NEED_TOUCH_EVENTS = 25;
+ static final int SYNC_SCROLL_TO_MSG_ID = 13;
+ static final int NEW_PICTURE_MSG_ID = 14;
+ static final int UPDATE_TEXT_ENTRY_MSG_ID = 15;
+ static final int WEBCORE_INITIALIZED_MSG_ID = 16;
+ static final int UPDATE_TEXTFIELD_TEXT_MSG_ID = 17;
+ static final int DID_FIRST_LAYOUT_MSG_ID = 18;
+ static final int RECOMPUTE_FOCUS_MSG_ID = 19;
+
+ static final int MARK_NODE_INVALID_ID = 21;
+ static final int UPDATE_CLIPBOARD = 22;
+ static final int LONG_PRESS_CENTER = 23;
+ static final int PREVENT_TOUCH_ID = 24;
+ static final int WEBCORE_NEED_TOUCH_EVENTS = 25;
// obj=Rect in doc coordinates
- static final int INVAL_RECT_MSG_ID = 26;
-
+ static final int INVAL_RECT_MSG_ID = 26;
+
static final String[] HandlerDebugString = {
- "REMEMBER_PASSWORD", // = 1;
- "NEVER_REMEMBER_PASSWORD", // = 2;
- "SWITCH_TO_SHORTPRESS", // = 3;
- "SWITCH_TO_LONGPRESS", // = 4;
+ "REMEMBER_PASSWORD", // = 1;
+ "NEVER_REMEMBER_PASSWORD", // = 2;
+ "SWITCH_TO_SHORTPRESS", // = 3;
+ "SWITCH_TO_LONGPRESS", // = 4;
"5",
- "UPDATE_TEXT_ENTRY_ADAPTER", // = 6;
- "SWITCH_TO_ENTER", // = 7;
- "RESUME_WEBCORE_UPDATE", // = 8;
+ "REQUEST_FORM_DATA", // = 6;
+ "SWITCH_TO_CLICK", // = 7;
+ "RESUME_WEBCORE_UPDATE", // = 8;
"9",
"SCROLL_TO_MSG_ID", // = 10;
"SCROLL_BY_MSG_ID", // = 11;
@@ -383,10 +477,10 @@ public class WebView extends AbsoluteLayout
"UPDATE_TEXTFIELD_TEXT_MSG_ID", // = 17;
"DID_FIRST_LAYOUT_MSG_ID", // = 18;
"RECOMPUTE_FOCUS_MSG_ID", // = 19;
- "NOTIFY_FOCUS_SET_MSG_ID", // = 20;
+ "20",
"MARK_NODE_INVALID_ID", // = 21;
"UPDATE_CLIPBOARD", // = 22;
- "LONG_PRESS_ENTER", // = 23;
+ "LONG_PRESS_CENTER", // = 23;
"PREVENT_TOUCH_ID", // = 24;
"WEBCORE_NEED_TOUCH_EVENTS", // = 25;
"INVAL_RECT_MSG_ID" // = 26;
@@ -427,7 +521,7 @@ public class WebView extends AbsoluteLayout
private static final int SNAP_X_LOCK = 4;
private static final int SNAP_Y_LOCK = 5;
private boolean mSnapPositive;
-
+
// Used to match key downs and key ups
private boolean mGotKeyDown;
@@ -450,7 +544,7 @@ public class WebView extends AbsoluteLayout
* URI scheme for map address
*/
public static final String SCHEME_GEO = "geo:0,0?q=";
-
+
private int mBackgroundColor = Color.WHITE;
// Used to notify listeners of a new picture.
@@ -467,7 +561,8 @@ public class WebView extends AbsoluteLayout
public void onNewPicture(WebView view, Picture picture);
}
- public class HitTestResult {
+ // FIXME: Want to make this public, but need to change the API file.
+ public /*static*/ class HitTestResult {
/**
* Default HitTestResult, where the target is unknown
*/
@@ -537,7 +632,7 @@ public class WebView extends AbsoluteLayout
private ExtendedZoomControls mZoomControls;
private Runnable mZoomControlRunnable;
- private ZoomButtonsController mZoomButtonsController;
+ private ZoomButtonsController mZoomButtonsController;
private ImageView mZoomOverviewButton;
private ImageView mZoomFitPageButton;
@@ -562,11 +657,11 @@ public class WebView extends AbsoluteLayout
} else {
zoomOut();
}
-
+
updateZoomButtonsEnabled();
}
};
-
+
/**
* Construct a new WebView with a Context object.
* @param context A Context object used to access application assets.
@@ -597,11 +692,6 @@ public class WebView extends AbsoluteLayout
mCallbackProxy = new CallbackProxy(context, this);
mWebViewCore = new WebViewCore(context, this, mCallbackProxy);
mDatabase = WebViewDatabase.getInstance(context);
- mFocusData = new WebViewCore.FocusData();
- mFocusData.mFrame = 0;
- mFocusData.mNode = 0;
- mFocusData.mX = 0;
- mFocusData.mY = 0;
mScroller = new Scroller(context);
initZoomController(context);
@@ -868,7 +958,7 @@ public class WebView extends AbsoluteLayout
clearTextEntry();
if (mWebViewCore != null) {
// Set the handlers to null before destroying WebViewCore so no
- // more messages will be posted.
+ // more messages will be posted.
mCallbackProxy.setWebViewClient(null);
mCallbackProxy.setWebChromeClient(null);
// Tell WebViewCore to destroy itself
@@ -899,12 +989,12 @@ public class WebView extends AbsoluteLayout
/**
* If platform notifications are enabled, this should be called
- * from onPause() or onStop().
+ * from the Activity's onPause() or onStop().
*/
public static void disablePlatformNotifications() {
Network.disablePlatformNotifications();
}
-
+
/**
* Inform WebView of the network state. This is used to set
* the javascript property window.navigator.isOnline and
@@ -917,7 +1007,7 @@ public class WebView extends AbsoluteLayout
}
/**
- * Save the state of this WebView used in
+ * Save the state of this WebView used in
* {@link android.app.Activity#onSaveInstanceState}. Please note that this
* method no longer stores the display data for this WebView. The previous
* behavior could potentially leak files if {@link #restoreState} was never
@@ -1048,10 +1138,10 @@ public class WebView extends AbsoluteLayout
/**
* Restore the state of this WebView from the given map used in
- * {@link android.app.Activity#onRestoreInstanceState}. This method should
- * be called to restore the state of the WebView before using the object. If
- * it is called after the WebView has had a chance to build state (load
- * pages, create a back/forward list, etc.) there may be undesirable
+ * {@link android.app.Activity#onRestoreInstanceState}. This method should
+ * be called to restore the state of the WebView before using the object. If
+ * it is called after the WebView has had a chance to build state (load
+ * pages, create a back/forward list, etc.) there may be undesirable
* side-effects. Please note that this method no longer restores the
* display data for this WebView. See {@link #savePicture} and {@link
* #restorePicture} for saving and restoring the display data.
@@ -1118,6 +1208,29 @@ public class WebView extends AbsoluteLayout
}
/**
+ * Load the url with postData using "POST" method into the WebView. If url
+ * is not a network url, it will be loaded with {link
+ * {@link #loadUrl(String)} instead.
+ *
+ * @param url The url of the resource to load.
+ * @param postData The data will be passed to "POST" request.
+ *
+ * @hide pending API solidification
+ */
+ public void postUrl(String url, byte[] postData) {
+ if (URLUtil.isNetworkUrl(url)) {
+ switchOutDrawHistory();
+ HashMap arg = new HashMap();
+ arg.put("url", url);
+ arg.put("data", postData);
+ mWebViewCore.sendMessage(EventHub.POST_URL, arg);
+ clearTextEntry();
+ } else {
+ loadUrl(url);
+ }
+ }
+
+ /**
* Load the given data into the WebView. This will load the data into
* WebView using the data: scheme. Content loaded through this mechanism
* does not have the ability to load content from the network.
@@ -1143,7 +1256,7 @@ public class WebView extends AbsoluteLayout
* able to access asset files. If the baseUrl is anything other than
* http(s)/ftp(s)/about/javascript as scheme, you can access asset files for
* sub resources.
- *
+ *
* @param baseUrl Url to resolve relative paths with, if null defaults to
* "about:blank"
* @param data A String of data in the given encoding.
@@ -1154,7 +1267,7 @@ public class WebView extends AbsoluteLayout
*/
public void loadDataWithBaseURL(String baseUrl, String data,
String mimeType, String encoding, String failUrl) {
-
+
if (baseUrl != null && baseUrl.toLowerCase().startsWith("data:")) {
loadData(data, mimeType, encoding);
return;
@@ -1275,7 +1388,7 @@ public class WebView extends AbsoluteLayout
ignoreSnapshot ? 1 : 0);
}
}
-
+
private boolean extendScroll(int y) {
int finalY = mScroller.getFinalY();
int newY = pinLocY(finalY + y);
@@ -1284,7 +1397,7 @@ public class WebView extends AbsoluteLayout
mScroller.extendDuration(computeDuration(0, y));
return true;
}
-
+
/**
* Scroll the contents of the view up by half the view size
* @param top true to jump to the top of the page
@@ -1308,10 +1421,10 @@ public class WebView extends AbsoluteLayout
y = -h / 2;
}
mUserScroll = true;
- return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
+ return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
: extendScroll(y);
}
-
+
/**
* Scroll the contents of the view down by half the page size
* @param bottom true to jump to bottom of page
@@ -1334,7 +1447,7 @@ public class WebView extends AbsoluteLayout
y = h / 2;
}
mUserScroll = true;
- return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
+ return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
: extendScroll(y);
}
@@ -1347,7 +1460,7 @@ public class WebView extends AbsoluteLayout
mContentHeight = 0;
mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT);
}
-
+
/**
* Return a new picture that captures the current display of the webview.
* This is a copy of the display, and will be unaffected if the webview
@@ -1358,7 +1471,7 @@ public class WebView extends AbsoluteLayout
* bounds of the view.
*/
public Picture capturePicture() {
- if (null == mWebViewCore) return null; // check for out of memory tab
+ if (null == mWebViewCore) return null; // check for out of memory tab
return mWebViewCore.copyContentPicture();
}
@@ -1366,17 +1479,17 @@ public class WebView extends AbsoluteLayout
* Return true if the browser is displaying a TextView for text input.
*/
private boolean inEditingMode() {
- return mTextEntry != null && mTextEntry.getParent() != null
- && mTextEntry.hasFocus();
+ return mWebTextView != null && mWebTextView.getParent() != null
+ && mWebTextView.hasFocus();
}
private void clearTextEntry() {
if (inEditingMode()) {
- mTextEntry.remove();
+ mWebTextView.remove();
}
}
- /**
+ /**
* Return the current scale of the WebView
* @return The current scale.
*/
@@ -1440,26 +1553,26 @@ public class WebView extends AbsoluteLayout
}
HitTestResult result = new HitTestResult();
-
- if (nativeUpdateFocusNode()) {
- FocusNode node = mFocusNode;
- if (node.mIsTextField || node.mIsTextArea) {
+ if (nativeHasCursorNode()) {
+ if (nativeCursorIsTextInput()) {
result.setType(HitTestResult.EDIT_TEXT_TYPE);
- } else if (node.mText != null) {
- String text = node.mText;
- if (text.startsWith(SCHEME_TEL)) {
- result.setType(HitTestResult.PHONE_TYPE);
- result.setExtra(text.substring(SCHEME_TEL.length()));
- } else if (text.startsWith(SCHEME_MAILTO)) {
- result.setType(HitTestResult.EMAIL_TYPE);
- result.setExtra(text.substring(SCHEME_MAILTO.length()));
- } else if (text.startsWith(SCHEME_GEO)) {
- result.setType(HitTestResult.GEO_TYPE);
- result.setExtra(URLDecoder.decode(text
- .substring(SCHEME_GEO.length())));
- } else if (node.mIsAnchor) {
- result.setType(HitTestResult.SRC_ANCHOR_TYPE);
- result.setExtra(text);
+ } else {
+ String text = nativeCursorText();
+ if (text != null) {
+ if (text.startsWith(SCHEME_TEL)) {
+ result.setType(HitTestResult.PHONE_TYPE);
+ result.setExtra(text.substring(SCHEME_TEL.length()));
+ } else if (text.startsWith(SCHEME_MAILTO)) {
+ result.setType(HitTestResult.EMAIL_TYPE);
+ result.setExtra(text.substring(SCHEME_MAILTO.length()));
+ } else if (text.startsWith(SCHEME_GEO)) {
+ result.setType(HitTestResult.GEO_TYPE);
+ result.setExtra(URLDecoder.decode(text
+ .substring(SCHEME_GEO.length())));
+ } else if (nativeCursorIsAnchor()) {
+ result.setType(HitTestResult.SRC_ANCHOR_TYPE);
+ result.setExtra(text);
+ }
}
}
}
@@ -1471,8 +1584,8 @@ public class WebView extends AbsoluteLayout
int contentY = viewToContent((int) mLastTouchY + mScrollY);
String text = nativeImageURI(contentX, contentY);
if (text != null) {
- result.setType(type == HitTestResult.UNKNOWN_TYPE ?
- HitTestResult.IMAGE_TYPE :
+ result.setType(type == HitTestResult.UNKNOWN_TYPE ?
+ HitTestResult.IMAGE_TYPE :
HitTestResult.SRC_IMAGE_ANCHOR_TYPE);
result.setExtra(text);
}
@@ -1484,7 +1597,7 @@ public class WebView extends AbsoluteLayout
* Request the href of an anchor element due to getFocusNodePath returning
* "href." If hrefMsg is null, this method returns immediately and does not
* dispatch hrefMsg to its target.
- *
+ *
* @param hrefMsg This message will be dispatched with the result of the
* request as the data member with "url" as key. The result can
* be null.
@@ -1493,22 +1606,20 @@ public class WebView extends AbsoluteLayout
if (hrefMsg == null || mNativeClass == 0) {
return;
}
- if (nativeUpdateFocusNode()) {
- FocusNode node = mFocusNode;
- if (node.mIsAnchor) {
- // NOTE: We may already have the url of the anchor stored in
- // node.mText but it may be out of date or the caller may want
- // to know about javascript urls.
- mWebViewCore.sendMessage(EventHub.REQUEST_FOCUS_HREF,
- node.mFramePointer, node.mNodePointer, hrefMsg);
- }
+ if (nativeCursorIsAnchor()) {
+ // NOTE: We may already have the url of the anchor stored in
+ // node.mText but it may be out of date or the caller may want
+ // to know about javascript urls.
+ mWebViewCore.sendMessage(EventHub.REQUEST_FOCUS_HREF,
+ nativeCursorFramePointer(), nativeCursorNodePointer(),
+ hrefMsg);
}
}
-
+
/**
* Request the url of the image last touched by the user. msg will be sent
* to its target with a String representing the url as its object.
- *
+ *
* @param msg This message will be dispatched with the result of the request
* as the data member with "url" as key. The result can be null.
*/
@@ -1583,7 +1694,7 @@ public class WebView extends AbsoluteLayout
if ((w | h) == 0) {
return;
}
-
+
// don't abort a scroll animation if we didn't change anything
if (mContentWidth != w || mContentHeight != h) {
// record new dimensions
@@ -1643,7 +1754,7 @@ public class WebView extends AbsoluteLayout
mActualScale = scale;
mInvActualScale = 1 / scale;
- // as we don't have animation for scaling, don't do animation
+ // as we don't have animation for scaling, don't do animation
// for scrolling, as it causes weird intermediate state
// pinScrollTo(Math.round(sx), Math.round(sy));
mScrollX = pinLocX(Math.round(sx));
@@ -1767,10 +1878,10 @@ public class WebView extends AbsoluteLayout
WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
return h != null ? h.getUrl() : null;
}
-
+
/**
- * Get the original url for the current page. This is not always the same
- * as the url passed to WebViewClient.onPageStarted because although the
+ * Get the original url for the current page. This is not always the same
+ * as the url passed to WebViewClient.onPageStarted because although the
* load for that url has begun, the current page may not have changed.
* Also, there may have been redirects resulting in a different url to that
* originally requested.
@@ -1808,7 +1919,7 @@ public class WebView extends AbsoluteLayout
public int getProgress() {
return mCallbackProxy.getProgress();
}
-
+
/**
* @return the height of the HTML content.
*/
@@ -1817,30 +1928,68 @@ public class WebView extends AbsoluteLayout
}
/**
- * Pause all layout, parsing, and javascript timers. This can be useful if
- * the WebView is not visible or the application has been paused.
+ * Pause all layout, parsing, and javascript timers for all webviews. This
+ * is a global requests, not restricted to just this webview. This can be
+ * useful if the application has been paused.
*/
public void pauseTimers() {
mWebViewCore.sendMessage(EventHub.PAUSE_TIMERS);
}
/**
- * Resume all layout, parsing, and javascript timers. This will resume
- * dispatching all timers.
+ * Resume all layout, parsing, and javascript timers for all webviews.
+ * This will resume dispatching all timers.
*/
public void resumeTimers() {
mWebViewCore.sendMessage(EventHub.RESUME_TIMERS);
}
/**
- * Clear the resource cache. This will cause resources to be re-downloaded
- * if accessed again.
- * <p>
- * Note: this really needs to be a static method as it clears cache for all
- * WebView. But we need mWebViewCore to send message to WebCore thread, so
- * we can't make this static.
+ * Call this to pause any extra processing associated with this view and
+ * its associated DOM/plugins/javascript/etc. For example, if the view is
+ * taken offscreen, this could be called to reduce unnecessary CPU and/or
+ * network traffic. When the view is again "active", call onResume().
+ *
+ * Note that this differs from pauseTimers(), which affects all views/DOMs
+ * @hide
+ */
+ public void onPause() {
+ if (!mIsPaused) {
+ mIsPaused = true;
+ mWebViewCore.sendMessage(EventHub.ON_PAUSE);
+ }
+ }
+
+ /**
+ * Call this to balanace a previous call to onPause()
+ * @hide
+ */
+ public void onResume() {
+ if (mIsPaused) {
+ mIsPaused = false;
+ mWebViewCore.sendMessage(EventHub.ON_RESUME);
+ }
+ }
+
+ /**
+ * Returns true if the view is paused, meaning onPause() was called. Calling
+ * onResume() sets the paused state back to false.
+ * @hide
+ */
+ public boolean isPaused() {
+ return mIsPaused;
+ }
+
+ /**
+ * Clear the resource cache. Note that the cache is per-application, so
+ * this will clear the cache for all WebViews used.
+ *
+ * @param includeDiskFiles If false, only the RAM cache is cleared.
*/
public void clearCache(boolean includeDiskFiles) {
+ // Note: this really needs to be a static method as it clears cache for all
+ // WebView. But we need mWebViewCore to send message to WebCore thread, so
+ // we can't make this static.
mWebViewCore.sendMessage(EventHub.CLEAR_CACHE,
includeDiskFiles ? 1 : 0, 0);
}
@@ -1852,7 +2001,7 @@ public class WebView extends AbsoluteLayout
public void clearFormData() {
if (inEditingMode()) {
AutoCompleteAdapter adapter = null;
- mTextEntry.setAdapterCustom(adapter);
+ mWebTextView.setAdapterCustom(adapter);
}
}
@@ -1886,7 +2035,7 @@ public class WebView extends AbsoluteLayout
/*
* Highlight and scroll to the next occurance of String in findAll.
- * Wraps the page infinitely, and scrolls. Must be called after
+ * Wraps the page infinitely, and scrolls. Must be called after
* calling findAll.
*
* @param forward Direction to search.
@@ -1912,11 +2061,8 @@ public class WebView extends AbsoluteLayout
// or not we draw the highlights for matches.
private boolean mFindIsUp;
- private native int nativeFindAll(String findLower, String findUpper);
- private native void nativeFindNext(boolean forward);
-
/**
- * Return the first substring consisting of the address of a physical
+ * Return the first substring consisting of the address of a physical
* location. Currently, only addresses in the United States are detected,
* and consist of:
* - a house number
@@ -1929,7 +2075,7 @@ public class WebView extends AbsoluteLayout
* All names must be correctly capitalized, and the zip code, if present,
* must be valid for the state. The street type must be a standard USPS
* spelling or abbreviation. The state or territory must also be spelled
- * or abbreviated using USPS standards. The house number may not exceed
+ * or abbreviated using USPS standards. The house number may not exceed
* five digits.
* @param addr The string to search for addresses.
*
@@ -2220,16 +2366,10 @@ public class WebView extends AbsoluteLayout
}
/**
- * Signal the WebCore thread to refresh its list of plugins. Use
- * this if the directory contents of one of the plugin directories
- * has been modified and needs its changes reflecting. May cause
- * plugin load and/or unload.
- * @param reloadOpenPages Set to true to reload all open pages.
+ * TODO: need to add @Deprecated
*/
public void refreshPlugins(boolean reloadOpenPages) {
- if (mWebViewCore != null) {
- mWebViewCore.sendMessage(EventHub.REFRESH_PLUGINS, reloadOpenPages);
- }
+ PluginManager.getInstance(mContext).refreshPlugins(reloadOpenPages);
}
//-------------------------------------------------------------------------
@@ -2240,7 +2380,7 @@ public class WebView extends AbsoluteLayout
protected void finalize() throws Throwable {
destroy();
}
-
+
@Override
protected void onDraw(Canvas canvas) {
// if mNativeClass is 0, the WebView has been destroyed. Do nothing.
@@ -2249,7 +2389,7 @@ public class WebView extends AbsoluteLayout
}
if (mWebViewCore.mEndScaleZoom) {
mWebViewCore.mEndScaleZoom = false;
- if (mTouchMode >= FIRST_SCROLL_ZOOM
+ if (mTouchMode >= FIRST_SCROLL_ZOOM
&& mTouchMode <= LAST_SCROLL_ZOOM) {
setHorizontalScrollBarEnabled(true);
setVerticalScrollBarEnabled(true);
@@ -2271,11 +2411,11 @@ public class WebView extends AbsoluteLayout
// need to check it again.
nativeRecordButtons(hasFocus() && hasWindowFocus(),
mTouchMode == TOUCH_SHORTPRESS_START_MODE
- || mTrackballDown || mGotEnterDown, false);
- drawCoreAndFocusRing(canvas, mBackgroundColor, mDrawFocusRing);
+ || mTrackballDown || mGotCenterDown, false);
+ drawCoreAndCursorRing(canvas, mBackgroundColor, mDrawCursorRing);
}
canvas.restoreToCount(sc);
-
+
if (AUTO_REDRAW_HACK && mAutoRedraw) {
invalidate();
}
@@ -2292,13 +2432,13 @@ public class WebView extends AbsoluteLayout
@Override
public boolean performLongClick() {
if (inEditingMode()) {
- return mTextEntry.performLongClick();
+ return mWebTextView.performLongClick();
} else {
return super.performLongClick();
}
}
- private void drawCoreAndFocusRing(Canvas canvas, int color,
+ private void drawCoreAndCursorRing(Canvas canvas, int color,
boolean drawFocus) {
if (mDrawHistory) {
canvas.scale(mActualScale, mActualScale);
@@ -2307,14 +2447,14 @@ public class WebView extends AbsoluteLayout
}
boolean animateZoom = mZoomScale != 0;
- boolean animateScroll = !mScroller.isFinished()
+ boolean animateScroll = !mScroller.isFinished()
|| mVelocityTracker != null;
if (animateZoom) {
float zoomScale;
int interval = (int) (SystemClock.uptimeMillis() - mZoomStart);
if (interval < ZOOM_ANIMATION_LENGTH) {
float ratio = (float) interval / ZOOM_ANIMATION_LENGTH;
- zoomScale = 1.0f / (mInvInitialZoomScale
+ zoomScale = 1.0f / (mInvInitialZoomScale
+ (mInvFinalZoomScale - mInvInitialZoomScale) * ratio);
invalidate();
} else {
@@ -2354,7 +2494,7 @@ public class WebView extends AbsoluteLayout
if (mTouchSelection) {
nativeDrawSelectionRegion(canvas);
} else {
- nativeDrawSelection(canvas, mSelectX, mSelectY,
+ nativeDrawSelection(canvas, mSelectX, mSelectY,
mExtendSelection);
}
} else if (drawFocus) {
@@ -2368,7 +2508,7 @@ public class WebView extends AbsoluteLayout
LONG_PRESS_TIMEOUT);
}
}
- nativeDrawFocusRing(canvas);
+ nativeDrawCursorRing(canvas);
}
// When the FindDialog is up, only draw the matches if we are not in
// the process of scrolling them into view.
@@ -2377,14 +2517,12 @@ public class WebView extends AbsoluteLayout
}
}
- private native void nativeDrawMatches(Canvas canvas);
-
private float scrollZoomGridScale(float invScale) {
- float griddedInvScale = (int) (invScale * SCROLL_ZOOM_GRID)
+ float griddedInvScale = (int) (invScale * SCROLL_ZOOM_GRID)
/ (float) SCROLL_ZOOM_GRID;
return 1.0f / griddedInvScale;
}
-
+
private float scrollZoomX(float scale) {
int width = getViewWidth();
float maxScrollZoomX = mContentWidth * scale - width;
@@ -2400,7 +2538,7 @@ public class WebView extends AbsoluteLayout
return -(maxScrollZoomY > 0 ? mZoomScrollY * maxScrollZoomY / maxY
: maxScrollZoomY / 2);
}
-
+
private void drawMagnifyFrame(Canvas canvas, Rect frame, Paint paint) {
final float ADORNMENT_LEN = 16.0f;
float width = frame.width();
@@ -2421,13 +2559,13 @@ public class WebView extends AbsoluteLayout
path.offset(frame.left, frame.top);
canvas.drawPath(path, paint);
}
-
- // Returns frame surrounding magified portion of screen while
+
+ // Returns frame surrounding magified portion of screen while
// scroll-zoom is enabled. The frame is also used to center the
// zoom-in zoom-out points at the start and end of the animation.
private Rect scrollZoomFrame(int width, int height, float halfScale) {
Rect scrollFrame = new Rect();
- scrollFrame.set(mZoomScrollX, mZoomScrollY,
+ scrollFrame.set(mZoomScrollX, mZoomScrollY,
mZoomScrollX + width, mZoomScrollY + height);
if (mContentWidth * mZoomScrollLimit < width) {
float scale = zoomFrameScaleX(width, halfScale, 1.0f);
@@ -2443,37 +2581,37 @@ public class WebView extends AbsoluteLayout
}
return scrollFrame;
}
-
+
private float zoomFrameScaleX(int width, float halfScale, float noScale) {
// mContentWidth > width > mContentWidth * mZoomScrollLimit
if (mContentWidth <= width) {
return halfScale;
}
- float part = (width - mContentWidth * mZoomScrollLimit)
+ float part = (width - mContentWidth * mZoomScrollLimit)
/ (width * (1 - mZoomScrollLimit));
return halfScale * part + noScale * (1.0f - part);
}
-
+
private float zoomFrameScaleY(int height, float halfScale, float noScale) {
if (mContentHeight <= height) {
return halfScale;
}
- float part = (height - mContentHeight * mZoomScrollLimit)
+ float part = (height - mContentHeight * mZoomScrollLimit)
/ (height * (1 - mZoomScrollLimit));
return halfScale * part + noScale * (1.0f - part);
}
-
+
private float scrollZoomMagScale(float invScale) {
return (invScale * 2 + mInvActualScale) / 3;
}
-
+
private void scrollZoomDraw(Canvas canvas) {
- float invScale = mZoomScrollInvLimit;
+ float invScale = mZoomScrollInvLimit;
int elapsed = 0;
if (mTouchMode != SCROLL_ZOOM_OUT) {
- elapsed = (int) Math.min(System.currentTimeMillis()
+ elapsed = (int) Math.min(System.currentTimeMillis()
- mZoomScrollStart, SCROLL_ZOOM_DURATION);
- float transitionScale = (mZoomScrollInvLimit - mInvActualScale)
+ float transitionScale = (mZoomScrollInvLimit - mInvActualScale)
* elapsed / SCROLL_ZOOM_DURATION;
if (mTouchMode == SCROLL_ZOOM_ANIMATION_OUT) {
invScale = mInvActualScale + transitionScale;
@@ -2491,9 +2629,9 @@ public class WebView extends AbsoluteLayout
if (mTouchMode == SCROLL_ZOOM_ANIMATION_IN) {
setHorizontalScrollBarEnabled(true);
setVerticalScrollBarEnabled(true);
- updateTextEntry();
- scrollTo((int) (scrollFrame.centerX() * mActualScale)
- - (width >> 1), (int) (scrollFrame.centerY()
+ rebuildWebTextView();
+ scrollTo((int) (scrollFrame.centerX() * mActualScale)
+ - (width >> 1), (int) (scrollFrame.centerY()
* mActualScale) - (height >> 1));
mTouchMode = TOUCH_DONE_MODE;
} else {
@@ -2502,10 +2640,10 @@ public class WebView extends AbsoluteLayout
}
float newX = scrollZoomX(scale);
float newY = scrollZoomY(scale);
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "scrollZoomDraw scale=" + scale + " + (" + newX
+ ", " + newY + ") mZoomScroll=(" + mZoomScrollX + ", "
- + mZoomScrollY + ")" + " invScale=" + invScale + " scale="
+ + mZoomScrollY + ")" + " invScale=" + invScale + " scale="
+ scale);
}
canvas.translate(newX, newY);
@@ -2549,8 +2687,8 @@ public class WebView extends AbsoluteLayout
}
canvas.scale(halfScale, halfScale, mZoomScrollX + width * halfX
, mZoomScrollY + height * halfY);
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "scrollZoomDraw halfScale=" + halfScale + " w/h=("
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "scrollZoomDraw halfScale=" + halfScale + " w/h=("
+ width + ", " + height + ") half=(" + halfX + ", "
+ halfY + ")");
}
@@ -2578,7 +2716,7 @@ public class WebView extends AbsoluteLayout
, Math.max(0, (int) ((x - left) / scale)));
mZoomScrollY = Math.min(mContentHeight - height
, Math.max(0, (int) ((y - top) / scale)));
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "zoomScrollTap scale=" + scale + " + (" + left
+ ", " + top + ") mZoomScroll=(" + mZoomScrollX + ", "
+ mZoomScrollY + ")" + " x=" + x + " y=" + y);
@@ -2595,7 +2733,7 @@ public class WebView extends AbsoluteLayout
float y = (float) height / (float) mContentHeight;
mZoomScrollLimit = Math.max(DEFAULT_MIN_ZOOM_SCALE, Math.min(x, y));
mZoomScrollInvLimit = 1.0f / mZoomScrollLimit;
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "canZoomScrollOut"
+ " mInvActualScale=" + mInvActualScale
+ " mZoomScrollLimit=" + mZoomScrollLimit
@@ -2610,7 +2748,7 @@ public class WebView extends AbsoluteLayout
return mContentWidth >= width * limit
|| mContentHeight >= height * limit;
}
-
+
private void startZoomScrollOut() {
setHorizontalScrollBarEnabled(false);
setVerticalScrollBarEnabled(false);
@@ -2636,18 +2774,18 @@ public class WebView extends AbsoluteLayout
mZoomScrollStart = System.currentTimeMillis();
Rect zoomFrame = scrollZoomFrame(width, height
, scrollZoomMagScale(mZoomScrollInvLimit));
- mZoomScrollX = Math.max(0, (int) ((mScrollX + halfW) * mInvActualScale)
+ mZoomScrollX = Math.max(0, (int) ((mScrollX + halfW) * mInvActualScale)
- (zoomFrame.width() >> 1));
- mZoomScrollY = Math.max(0, (int) ((mScrollY + halfH) * mInvActualScale)
+ mZoomScrollY = Math.max(0, (int) ((mScrollY + halfH) * mInvActualScale)
- (zoomFrame.height() >> 1));
scrollTo(0, 0); // triggers inval, starts animation
clearTextEntry();
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "startZoomScrollOut mZoomScroll=("
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "startZoomScrollOut mZoomScroll=("
+ mZoomScrollX + ", " + mZoomScrollY +")");
}
}
-
+
private void zoomScrollOut() {
if (canZoomScrollOut() == false) {
mTouchMode = TOUCH_DONE_MODE;
@@ -2659,7 +2797,7 @@ public class WebView extends AbsoluteLayout
}
private void moveZoomScrollWindow(float x, float y) {
- if (Math.abs(x - mLastZoomScrollRawX) < 1.5f
+ if (Math.abs(x - mLastZoomScrollRawX) < 1.5f
&& Math.abs(y - mLastZoomScrollRawY) < 1.5f) {
return;
}
@@ -2671,12 +2809,12 @@ public class WebView extends AbsoluteLayout
int height = getViewHeight();
int maxZoomX = mContentWidth - width;
if (maxZoomX > 0) {
- int maxScreenX = width - (int) Math.ceil(width
+ int maxScreenX = width - (int) Math.ceil(width
* mZoomScrollLimit) - SCROLL_ZOOM_FINGER_BUFFER;
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "moveZoomScrollWindow-X"
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "moveZoomScrollWindow-X"
+ " maxScreenX=" + maxScreenX + " width=" + width
- + " mZoomScrollLimit=" + mZoomScrollLimit + " x=" + x);
+ + " mZoomScrollLimit=" + mZoomScrollLimit + " x=" + x);
}
x += maxScreenX * mLastScrollX / maxZoomX - mLastTouchX;
x *= Math.max(maxZoomX / maxScreenX, mZoomScrollInvLimit);
@@ -2684,12 +2822,12 @@ public class WebView extends AbsoluteLayout
}
int maxZoomY = mContentHeight - height;
if (maxZoomY > 0) {
- int maxScreenY = height - (int) Math.ceil(height
+ int maxScreenY = height - (int) Math.ceil(height
* mZoomScrollLimit) - SCROLL_ZOOM_FINGER_BUFFER;
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "moveZoomScrollWindow-Y"
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "moveZoomScrollWindow-Y"
+ " maxScreenY=" + maxScreenY + " height=" + height
- + " mZoomScrollLimit=" + mZoomScrollLimit + " y=" + y);
+ + " mZoomScrollLimit=" + mZoomScrollLimit + " y=" + y);
}
y += maxScreenY * mLastScrollY / maxZoomY - mLastTouchY;
y *= Math.max(maxZoomY / maxScreenY, mZoomScrollInvLimit);
@@ -2698,12 +2836,12 @@ public class WebView extends AbsoluteLayout
if (oldX != mZoomScrollX || oldY != mZoomScrollY) {
invalidate();
}
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "moveZoomScrollWindow"
- + " scrollTo=(" + mZoomScrollX + ", " + mZoomScrollY + ")"
- + " mLastTouch=(" + mLastTouchX + ", " + mLastTouchY + ")"
- + " maxZoom=(" + maxZoomX + ", " + maxZoomY + ")"
- + " last=("+mLastScrollX+", "+mLastScrollY+")"
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "moveZoomScrollWindow"
+ + " scrollTo=(" + mZoomScrollX + ", " + mZoomScrollY + ")"
+ + " mLastTouch=(" + mLastTouchX + ", " + mLastTouchY + ")"
+ + " maxZoom=(" + maxZoomX + ", " + maxZoomY + ")"
+ + " last=("+mLastScrollX+", "+mLastScrollY+")"
+ " x=" + x + " y=" + y);
}
}
@@ -2748,7 +2886,7 @@ public class WebView extends AbsoluteLayout
// Should only be called in UI thread
void switchOutDrawHistory() {
if (null == mWebViewCore) return; // CallbackProxy may trigger this
- if (mDrawHistory) {
+ if (mDrawHistory && mWebViewCore.pictureReady()) {
mDrawHistory = false;
invalidate();
int oldScrollX = mScrollX;
@@ -2764,72 +2902,27 @@ public class WebView extends AbsoluteLayout
}
}
- /**
- * Class representing the node which is focused.
- */
- private class FocusNode {
- public FocusNode() {
- mBounds = new Rect();
- }
- // Only to be called by JNI
- private void setAll(boolean isTextField, boolean isTextArea, boolean
- isPassword, boolean isAnchor, boolean isRtlText, int maxLength,
- int textSize, int boundsX, int boundsY, int boundsRight, int
- boundsBottom, int nodePointer, int framePointer, String text,
- String name, int rootTextGeneration) {
- mIsTextField = isTextField;
- mIsTextArea = isTextArea;
- mIsPassword = isPassword;
- mIsAnchor = isAnchor;
- mIsRtlText = isRtlText;
-
- mMaxLength = maxLength;
- mTextSize = textSize;
-
- mBounds.set(boundsX, boundsY, boundsRight, boundsBottom);
-
-
- mNodePointer = nodePointer;
- mFramePointer = framePointer;
- mText = text;
- mName = name;
- mRootTextGeneration = rootTextGeneration;
- }
- public boolean mIsTextField;
- public boolean mIsTextArea;
- public boolean mIsPassword;
- public boolean mIsAnchor;
- public boolean mIsRtlText;
-
- public int mSelectionStart;
- public int mSelectionEnd;
- public int mMaxLength;
- public int mTextSize;
-
- public Rect mBounds;
-
- public int mNodePointer;
- public int mFramePointer;
- public String mText;
- public String mName;
- public int mRootTextGeneration;
- }
-
- // Warning: ONLY use mFocusNode AFTER calling nativeUpdateFocusNode(),
- // and ONLY if it returns true;
- private FocusNode mFocusNode = new FocusNode();
-
+ WebViewCore.CursorData cursorData() {
+ WebViewCore.CursorData result = new WebViewCore.CursorData();
+ result.mMoveGeneration = nativeMoveGeneration();
+ result.mFrame = nativeCursorFramePointer();
+ result.mNode = nativeCursorNodePointer();
+ Rect bounds = nativeCursorNodeBounds();
+ result.mX = bounds.centerX();
+ result.mY = bounds.centerY();
+ return result;
+ }
+
/**
* Delete text from start to end in the focused textfield. If there is no
- * focus, or if start == end, silently fail. If start and end are out of
+ * focus, or if start == end, silently fail. If start and end are out of
* order, swap them.
* @param start Beginning of selection to delete.
* @param end End of selection to delete.
*/
/* package */ void deleteSelection(int start, int end) {
mTextGeneration++;
- mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, start, end,
- new WebViewCore.FocusData(mFocusData));
+ mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, start, end);
}
/**
@@ -2839,119 +2932,121 @@ public class WebView extends AbsoluteLayout
* @param end End of selection.
*/
/* package */ void setSelection(int start, int end) {
- mWebViewCore.sendMessage(EventHub.SET_SELECTION, start, end,
- new WebViewCore.FocusData(mFocusData));
+ mWebViewCore.sendMessage(EventHub.SET_SELECTION, start, end);
}
// Called by JNI when a touch event puts a textfield into focus.
private void displaySoftKeyboard() {
InputMethodManager imm = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.showSoftInput(mTextEntry, 0);
- mTextEntry.enableScrollOnScreen(true);
+ imm.showSoftInput(mWebTextView, 0);
+ mWebTextView.enableScrollOnScreen(true);
// Now we need to fake a touch event to place the cursor where the
// user touched.
AbsoluteLayout.LayoutParams lp = (AbsoluteLayout.LayoutParams)
- mTextEntry.getLayoutParams();
+ mWebTextView.getLayoutParams();
if (lp != null) {
// Take the last touch and adjust for the location of the
- // TextDialog.
+ // WebTextView.
float x = mLastTouchX + (float) (mScrollX - lp.x);
float y = mLastTouchY + (float) (mScrollY - lp.y);
- mTextEntry.fakeTouchEvent(x, y);
+ mWebTextView.fakeTouchEvent(x, y);
}
}
- private void updateTextEntry() {
- if (mTextEntry == null) {
- mTextEntry = new TextDialog(mContext, WebView.this);
- // Initialize our generation number.
- mTextGeneration = 0;
- }
+ /*
+ * This method checks the current focus and potentially rebuilds
+ * mWebTextView to have the appropriate properties, such as password,
+ * multiline, and what text it contains. It also removes it if necessary.
+ */
+ private void rebuildWebTextView() {
// If we do not have focus, do nothing until we gain focus.
- if (!hasFocus() && !mTextEntry.hasFocus()
- || (mTouchMode >= FIRST_SCROLL_ZOOM
+ if (!hasFocus() && (null == mWebTextView || !mWebTextView.hasFocus())
+ || (mTouchMode >= FIRST_SCROLL_ZOOM
&& mTouchMode <= LAST_SCROLL_ZOOM)) {
- mNeedsUpdateTextEntry = true;
+ mNeedsRebuildWebTextView = true;
return;
}
boolean alreadyThere = inEditingMode();
- if (0 == mNativeClass || !nativeUpdateFocusNode()) {
+ // inEditingMode can only return true if mWebTextView is non-null,
+ // so we can safely call remove() if (alreadyThere)
+ if (0 == mNativeClass || (!nativeFocusIsTextInput()
+ && !nativeCursorIsTextInput())) {
if (alreadyThere) {
- mTextEntry.remove();
+ mWebTextView.remove();
}
return;
}
- FocusNode node = mFocusNode;
- if (!node.mIsTextField && !node.mIsTextArea) {
- if (alreadyThere) {
- mTextEntry.remove();
- }
- return;
+ // At this point, we know we have found an input field, so go ahead
+ // and create the WebTextView if necessary.
+ if (mWebTextView == null) {
+ mWebTextView = new WebTextView(mContext, WebView.this);
+ // Initialize our generation number.
+ mTextGeneration = 0;
}
- mTextEntry.setTextSize(contentToView(node.mTextSize));
+ mWebTextView.setTextSize(contentToView(nativeFocusTextSize()));
Rect visibleRect = sendOurVisibleRect();
// Note that sendOurVisibleRect calls viewToContent, so the coordinates
// should be in content coordinates.
- if (!Rect.intersects(node.mBounds, visibleRect)) {
+ Rect bounds = nativeFocusNodeBounds();
+ if (!Rect.intersects(bounds, visibleRect)) {
// Node is not on screen, so do not bother.
return;
}
- int x = node.mBounds.left;
- int y = node.mBounds.top;
- int width = node.mBounds.width();
- int height = node.mBounds.height();
- if (alreadyThere && mTextEntry.isSameTextField(node.mNodePointer)) {
+ String text = nativeFocusText();
+ int nodePointer = nativeFocusNodePointer();
+ if (alreadyThere && mWebTextView.isSameTextField(nodePointer)) {
// It is possible that we have the same textfield, but it has moved,
// i.e. In the case of opening/closing the screen.
// In that case, we need to set the dimensions, but not the other
// aspects.
// We also need to restore the selection, which gets wrecked by
// calling setTextEntryRect.
- Spannable spannable = (Spannable) mTextEntry.getText();
+ Spannable spannable = (Spannable) mWebTextView.getText();
int start = Selection.getSelectionStart(spannable);
int end = Selection.getSelectionEnd(spannable);
- setTextEntryRect(x, y, width, height);
// If the text has been changed by webkit, update it. However, if
// there has been more UI text input, ignore it. We will receive
// another update when that text is recognized.
- if (node.mText != null && !node.mText.equals(spannable.toString())
- && node.mRootTextGeneration == mTextGeneration) {
- mTextEntry.setTextAndKeepSelection(node.mText);
+ if (text != null && !text.equals(spannable.toString())
+ && nativeTextGeneration() == mTextGeneration) {
+ mWebTextView.setTextAndKeepSelection(text);
} else {
Selection.setSelection(spannable, start, end);
}
} else {
- String text = node.mText;
- setTextEntryRect(x, y, width, height);
- mTextEntry.setGravity(node.mIsRtlText ? Gravity.RIGHT :
+ Rect vBox = contentToView(bounds);
+ mWebTextView.setRect(vBox.left, vBox.top, vBox.width(),
+ vBox.height());
+ mWebTextView.setGravity(nativeFocusIsRtlText() ? Gravity.RIGHT :
Gravity.NO_GRAVITY);
// this needs to be called before update adapter thread starts to
- // ensure the mTextEntry has the same node pointer
- mTextEntry.setNodePointer(node.mNodePointer);
+ // ensure the mWebTextView has the same node pointer
+ mWebTextView.setNodePointer(nodePointer);
int maxLength = -1;
- if (node.mIsTextField) {
- maxLength = node.mMaxLength;
+ boolean isTextField = nativeFocusIsTextField();
+ if (isTextField) {
+ maxLength = nativeFocusMaxLength();
+ String name = nativeFocusName();
if (mWebViewCore.getSettings().getSaveFormData()
- && node.mName != null) {
+ && name != null) {
HashMap data = new HashMap();
- data.put("text", node.mText);
+ data.put("text", text);
Message update = mPrivateHandler.obtainMessage(
- UPDATE_TEXT_ENTRY_ADAPTER, node.mNodePointer, 0,
- data);
- UpdateTextEntryAdapter updater = new UpdateTextEntryAdapter(
- node.mName, getUrl(), update);
+ REQUEST_FORM_DATA, nodePointer, 0, data);
+ RequestFormData updater = new RequestFormData(name,
+ getUrl(), update);
Thread t = new Thread(updater);
t.start();
}
}
- mTextEntry.setMaxLength(maxLength);
+ mWebTextView.setMaxLength(maxLength);
AutoCompleteAdapter adapter = null;
- mTextEntry.setAdapterCustom(adapter);
- mTextEntry.setSingleLine(node.mIsTextField);
- mTextEntry.setInPassword(node.mIsPassword);
+ mWebTextView.setAdapterCustom(adapter);
+ mWebTextView.setSingleLine(isTextField);
+ mWebTextView.setInPassword(nativeFocusIsPassword());
if (null == text) {
- mTextEntry.setText("", 0, 0);
+ mWebTextView.setText("", 0, 0);
} else {
// Change to true to enable the old style behavior, where
// entering a textfield/textarea always set the selection to the
@@ -2962,24 +3057,29 @@ public class WebView extends AbsoluteLayout
// textarea. Testing out a new behavior, where textfields set
// selection at the end, and textareas at the beginning.
if (false) {
- mTextEntry.setText(text, 0, text.length());
- } else if (node.mIsTextField) {
+ mWebTextView.setText(text, 0, text.length());
+ } else if (isTextField) {
int length = text.length();
- mTextEntry.setText(text, length, length);
+ mWebTextView.setText(text, length, length);
} else {
- mTextEntry.setText(text, 0, 0);
+ mWebTextView.setText(text, 0, 0);
}
}
- mTextEntry.requestFocus();
+ mWebTextView.requestFocus();
}
}
- private class UpdateTextEntryAdapter implements Runnable {
+ /*
+ * This class requests an Adapter for the WebTextView which shows past
+ * entries stored in the database. It is a Runnable so that it can be done
+ * in its own thread, without slowing down the UI.
+ */
+ private class RequestFormData implements Runnable {
private String mName;
private String mUrl;
private Message mUpdateMessage;
- public UpdateTextEntryAdapter(String name, String url, Message msg) {
+ public RequestFormData(String name, String url, Message msg) {
mName = name;
mUrl = url;
mUpdateMessage = msg;
@@ -2996,21 +3096,13 @@ public class WebView extends AbsoluteLayout
}
}
- private void setTextEntryRect(int x, int y, int width, int height) {
- x = contentToView(x);
- y = contentToView(y);
- width = contentToView(width);
- height = contentToView(height);
- mTextEntry.setRect(x, y, width, height);
- }
-
- // This is used to determine long press with the enter key, or
- // a center key. Does not affect long press with the trackball/touch.
- private boolean mGotEnterDown = false;
+ // This is used to determine long press with the center key. Does not
+ // affect long press with the trackball/touch.
+ private boolean mGotCenterDown = false;
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "keyDown at " + System.currentTimeMillis()
+ ", " + event);
}
@@ -3038,15 +3130,15 @@ public class WebView extends AbsoluteLayout
return false;
}
- if (mShiftIsPressed == false && nativeFocusNodeWantsKeyEvents() == false
- && (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
+ if (mShiftIsPressed == false && nativeCursorWantsKeyEvents() == false
+ && (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
|| keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT)) {
mExtendSelection = false;
mShiftIsPressed = true;
- if (nativeUpdateFocusNode()) {
- FocusNode node = mFocusNode;
- mSelectX = contentToView(node.mBounds.left);
- mSelectY = contentToView(node.mBounds.top);
+ if (nativeHasCursorNode()) {
+ Rect rect = nativeCursorNodeBounds();
+ mSelectX = contentToView(rect.left);
+ mSelectY = contentToView(rect.top);
} else {
mSelectX = mScrollX + (int) mLastTouchX;
mSelectY = mScrollY + (int) mLastTouchY;
@@ -3068,13 +3160,12 @@ public class WebView extends AbsoluteLayout
return false;
}
- if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER
- || keyCode == KeyEvent.KEYCODE_ENTER) {
+ if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
switchOutDrawHistory();
if (event.getRepeatCount() == 0) {
- mGotEnterDown = true;
+ mGotCenterDown = true;
mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(LONG_PRESS_ENTER), LONG_PRESS_TIMEOUT);
+ .obtainMessage(LONG_PRESS_CENTER), LONG_PRESS_TIMEOUT);
// Already checked mNativeClass, so we do not need to check it
// again.
nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
@@ -3084,6 +3175,15 @@ public class WebView extends AbsoluteLayout
return false;
}
+ if (keyCode != KeyEvent.KEYCODE_SHIFT_LEFT
+ && keyCode != KeyEvent.KEYCODE_SHIFT_RIGHT) {
+ // turn off copy select if a shift-key combo is pressed
+ mExtendSelection = mShiftIsPressed = false;
+ if (mTouchMode == TOUCH_SELECT_MODE) {
+ mTouchMode = TOUCH_INIT_MODE;
+ }
+ }
+
if (getSettings().getNavDump()) {
switch (keyCode) {
case KeyEvent.KEYCODE_4:
@@ -3113,7 +3213,7 @@ public class WebView extends AbsoluteLayout
}
// TODO: should we pass all the keys to DOM or check the meta tag
- if (nativeFocusNodeWantsKeyEvents() || true) {
+ if (nativeCursorWantsKeyEvents() || true) {
// pass the key to DOM
mWebViewCore.sendMessage(EventHub.KEY_DOWN, event);
// return true as DOM handles the key
@@ -3126,7 +3226,7 @@ public class WebView extends AbsoluteLayout
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "keyUp at " + System.currentTimeMillis()
+ ", " + event);
}
@@ -3136,10 +3236,9 @@ public class WebView extends AbsoluteLayout
}
// special CALL handling when focus node's href is "tel:XXX"
- if (keyCode == KeyEvent.KEYCODE_CALL && nativeUpdateFocusNode()) {
- FocusNode node = mFocusNode;
- String text = node.mText;
- if (!node.mIsTextField && !node.mIsTextArea && text != null
+ if (keyCode == KeyEvent.KEYCODE_CALL && nativeHasCursorNode()) {
+ String text = nativeCursorText();
+ if (!nativeCursorIsTextInput() && text != null
&& text.startsWith(SCHEME_TEL)) {
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(text));
getContext().startActivity(intent);
@@ -3166,7 +3265,7 @@ public class WebView extends AbsoluteLayout
return false;
}
- if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
+ if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
|| keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
if (commitCopy()) {
return true;
@@ -3180,55 +3279,30 @@ public class WebView extends AbsoluteLayout
return false;
}
- if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER
- || keyCode == KeyEvent.KEYCODE_ENTER) {
+ if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
// remove the long press message first
- mPrivateHandler.removeMessages(LONG_PRESS_ENTER);
- mGotEnterDown = false;
+ mPrivateHandler.removeMessages(LONG_PRESS_CENTER);
+ mGotCenterDown = false;
- if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode) {
- if (mShiftIsPressed) {
- return false;
- }
- if (getSettings().supportZoom()) {
- if (mTouchMode == TOUCH_DOUBLECLICK_MODE) {
- zoomScrollOut();
- } else {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "TOUCH_DOUBLECLICK_MODE");
- }
- mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(SWITCH_TO_ENTER), TAP_TIMEOUT);
- mTouchMode = TOUCH_DOUBLECLICK_MODE;
- }
- return true;
- }
+ if (mShiftIsPressed) {
+ return false;
}
-
- Rect visibleRect = sendOurVisibleRect();
- // Note that sendOurVisibleRect calls viewToContent, so the
- // coordinates should be in content coordinates.
- if (nativeUpdateFocusNode()) {
- if (Rect.intersects(mFocusNode.mBounds, visibleRect)) {
- nativeSetFollowedLink(true);
- mWebViewCore.sendMessage(EventHub.SET_FINAL_FOCUS,
- EventHub.BLOCK_FOCUS_CHANGE_UNTIL_KEY_UP, 0,
- new WebViewCore.FocusData(mFocusData));
- playSoundEffect(SoundEffectConstants.CLICK);
- if (!mCallbackProxy.uiOverrideUrlLoading(mFocusNode.mText)) {
- // use CLICK instead of KEY_DOWN/KEY_UP so that we can
- // trigger mouse click events
- mWebViewCore.sendMessage(EventHub.CLICK);
- }
+ if (getSettings().supportZoom()
+ && mTouchMode == TOUCH_DOUBLECLICK_MODE) {
+ zoomScrollOut();
+ } else {
+ mPrivateHandler.sendMessageDelayed(mPrivateHandler
+ .obtainMessage(SWITCH_TO_CLICK), TAP_TIMEOUT);
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "TOUCH_DOUBLECLICK_MODE");
}
- return true;
+ mTouchMode = TOUCH_DOUBLECLICK_MODE;
}
- // Bubble up the key event as WebView doesn't handle it
- return false;
+ return true;
}
// TODO: should we pass all the keys to DOM or check the meta tag
- if (nativeFocusNodeWantsKeyEvents() || true) {
+ if (nativeCursorWantsKeyEvents() || true) {
// pass the key to DOM
mWebViewCore.sendMessage(EventHub.KEY_UP, event);
// return true as DOM handles the key
@@ -3238,7 +3312,7 @@ public class WebView extends AbsoluteLayout
// Bubble up the key event as WebView doesn't handle it
return false;
}
-
+
/**
* @hide
*/
@@ -3295,15 +3369,15 @@ public class WebView extends AbsoluteLayout
// Clean up the zoom controller
mZoomButtonsController.setVisible(false);
}
-
+
// Implementation for OnHierarchyChangeListener
public void onChildViewAdded(View parent, View child) {}
-
+
public void onChildViewRemoved(View p, View child) {
if (child == this) {
if (inEditingMode()) {
clearTextEntry();
- mNeedsUpdateTextEntry = true;
+ mNeedsRebuildWebTextView = true;
}
}
}
@@ -3317,26 +3391,27 @@ public class WebView extends AbsoluteLayout
public void onGlobalFocusChanged(View oldFocus, View newFocus) {
}
- // To avoid drawing the focus ring, and remove the TextView when our window
+ // To avoid drawing the cursor ring, and remove the TextView when our window
// loses focus.
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
if (hasWindowFocus) {
if (hasFocus()) {
// If our window regained focus, and we have focus, then begin
- // drawing the focus ring, and restore the TextView if
+ // drawing the cursor ring, and restore the TextView if
// necessary.
- mDrawFocusRing = true;
- if (mNeedsUpdateTextEntry) {
- updateTextEntry();
+ mDrawCursorRing = true;
+ if (mNeedsRebuildWebTextView) {
+ rebuildWebTextView();
}
if (mNativeClass != 0) {
nativeRecordButtons(true, false, true);
}
+ setFocusControllerActive(true);
} else {
// If our window gained focus, but we do not have it, do not
- // draw the focus ring.
- mDrawFocusRing = false;
+ // draw the cursor ring.
+ mDrawCursorRing = false;
// We do not call nativeRecordButtons here because we assume
// that when we lost focus, or window focus, it got called with
// false for the first parameter
@@ -3345,42 +3420,57 @@ public class WebView extends AbsoluteLayout
if (getSettings().getBuiltInZoomControls() && !mZoomButtonsController.isVisible()) {
/*
* The zoom controls come in their own window, so our window
- * loses focus. Our policy is to not draw the focus ring if
+ * loses focus. Our policy is to not draw the cursor ring if
* our window is not focused, but this is an exception since
* the user can still navigate the web page with the zoom
* controls showing.
*/
- // If our window has lost focus, stop drawing the focus ring
- mDrawFocusRing = false;
+ // If our window has lost focus, stop drawing the cursor ring
+ mDrawCursorRing = false;
}
mGotKeyDown = false;
mShiftIsPressed = false;
if (mNativeClass != 0) {
nativeRecordButtons(false, false, true);
}
+ setFocusControllerActive(false);
}
invalidate();
super.onWindowFocusChanged(hasWindowFocus);
}
+ /*
+ * Pass a message to WebCore Thread, determining whether the WebCore::Page's
+ * FocusController is "active" so that it will draw the blinking cursor.
+ */
+ private void setFocusControllerActive(boolean active) {
+ if (mWebViewCore != null) {
+ mWebViewCore.sendMessage(EventHub.SET_ACTIVE, active ? 1 : 0, 0);
+ }
+ }
+
@Override
protected void onFocusChanged(boolean focused, int direction,
Rect previouslyFocusedRect) {
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "MT focusChanged " + focused + ", " + direction);
}
if (focused) {
// When we regain focus, if we have window focus, resume drawing
- // the focus ring, and add the TextView if necessary.
+ // the cursor ring, and add the TextView if necessary.
if (hasWindowFocus()) {
- mDrawFocusRing = true;
- if (mNeedsUpdateTextEntry) {
- updateTextEntry();
- mNeedsUpdateTextEntry = false;
+ mDrawCursorRing = true;
+ if (mNeedsRebuildWebTextView) {
+ rebuildWebTextView();
+ mNeedsRebuildWebTextView = false;
}
if (mNativeClass != 0) {
nativeRecordButtons(true, false, true);
}
+ // FIXME: This is unnecessary if we are gaining focus from the
+ // WebTextView. How can we tell if it was the last thing in
+ // focus?
+ setFocusControllerActive(true);
//} else {
// The WebView has gained focus while we do not have
// windowfocus. When our window lost focus, we should have
@@ -3388,12 +3478,13 @@ public class WebView extends AbsoluteLayout
}
} else {
// When we lost focus, unless focus went to the TextView (which is
- // true if we are in editing mode), stop drawing the focus ring.
+ // true if we are in editing mode), stop drawing the cursor ring.
if (!inEditingMode()) {
- mDrawFocusRing = false;
+ mDrawCursorRing = false;
if (mNativeClass != 0) {
nativeRecordButtons(false, false, true);
}
+ setFocusControllerActive(false);
}
mGotKeyDown = false;
}
@@ -3424,8 +3515,8 @@ public class WebView extends AbsoluteLayout
super.onScrollChanged(l, t, oldl, oldt);
sendOurVisibleRect();
}
-
-
+
+
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
boolean dispatch = true;
@@ -3469,7 +3560,7 @@ public class WebView extends AbsoluteLayout
return false;
}
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, ev + " at " + ev.getEventTime() + " mTouchMode="
+ mTouchMode);
}
@@ -3494,7 +3585,7 @@ public class WebView extends AbsoluteLayout
if (mForwardTouchEvents && mTouchMode != SCROLL_ZOOM_OUT
&& mTouchMode != SCROLL_ZOOM_ANIMATION_IN
&& mTouchMode != SCROLL_ZOOM_ANIMATION_OUT
- && (action != MotionEvent.ACTION_MOVE ||
+ && (action != MotionEvent.ACTION_MOVE ||
eventTime - mLastSentTouchTime > TOUCH_SENT_INTERVAL)) {
WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
ted.mAction = action;
@@ -3525,7 +3616,7 @@ public class WebView extends AbsoluteLayout
mSelectX = mScrollX + (int) x;
mSelectY = mScrollY + (int) y;
mTouchMode = TOUCH_SELECT_MODE;
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "select=" + mSelectX + "," + mSelectY);
}
nativeMoveSelection(viewToContent(mSelectX)
@@ -3553,7 +3644,7 @@ public class WebView extends AbsoluteLayout
break;
}
case MotionEvent.ACTION_MOVE: {
- if (mTouchMode == TOUCH_DONE_MODE
+ if (mTouchMode == TOUCH_DONE_MODE
|| mTouchMode == SCROLL_ZOOM_ANIMATION_IN
|| mTouchMode == SCROLL_ZOOM_ANIMATION_OUT) {
// no dragging during scroll zoom animation
@@ -3570,7 +3661,7 @@ public class WebView extends AbsoluteLayout
if (mTouchMode == TOUCH_SELECT_MODE) {
mSelectX = mScrollX + (int) x;
mSelectY = mScrollY + (int) y;
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "xtend=" + mSelectX + "," + mSelectY);
}
nativeMoveSelection(viewToContent(mSelectX)
@@ -3605,9 +3696,6 @@ public class WebView extends AbsoluteLayout
WebViewCore.pauseUpdate(mWebViewCore);
int contentX = viewToContent((int) x + mScrollX);
int contentY = viewToContent((int) y + mScrollY);
- if (inEditingMode()) {
- mTextEntry.updateCachedTextfield();
- }
nativeClearFocus(contentX, contentY);
// remove the zoom anchor if there is any
if (mZoomScale != 0) {
@@ -3618,7 +3706,7 @@ public class WebView extends AbsoluteLayout
if (settings.supportZoom()
&& settings.getBuiltInZoomControls()
&& !mZoomButtonsController.isVisible()
- && (canZoomScrollOut() ||
+ && (canZoomScrollOut() ||
mMinZoomScale < mMaxZoomScale)) {
mZoomButtonsController.setVisible(true);
}
@@ -3644,7 +3732,7 @@ public class WebView extends AbsoluteLayout
}
// reverse direction means lock in the snap mode
if ((ax > MAX_SLOPE_FOR_DIAG * ay) &&
- ((mSnapPositive &&
+ ((mSnapPositive &&
deltaX < -mMinLockSnapReverseDistance)
|| (!mSnapPositive &&
deltaX > mMinLockSnapReverseDistance))) {
@@ -3658,9 +3746,9 @@ public class WebView extends AbsoluteLayout
}
// reverse direction means lock in the snap mode
if ((ay > MAX_SLOPE_FOR_DIAG * ax) &&
- ((mSnapPositive &&
+ ((mSnapPositive &&
deltaY < -mMinLockSnapReverseDistance)
- || (!mSnapPositive &&
+ || (!mSnapPositive &&
deltaY > mMinLockSnapReverseDistance))) {
mSnapScrollMode = SNAP_Y_LOCK;
}
@@ -3725,7 +3813,7 @@ public class WebView extends AbsoluteLayout
// no action during scroll animation
break;
case SCROLL_ZOOM_OUT:
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "ACTION_UP SCROLL_ZOOM_OUT"
+ " eventTime - mLastTouchTime="
+ (eventTime - mLastTouchTime));
@@ -3785,16 +3873,13 @@ public class WebView extends AbsoluteLayout
mTouchMode = TOUCH_DONE_MODE;
int contentX = viewToContent((int) mLastTouchX + mScrollX);
int contentY = viewToContent((int) mLastTouchY + mScrollY);
- if (inEditingMode()) {
- mTextEntry.updateCachedTextfield();
- }
nativeClearFocus(contentX, contentY);
break;
}
}
return true;
}
-
+
private long mTrackballFirstTime = 0;
private long mTrackballLastTime = 0;
private float mTrackballRemainsX = 0.0f;
@@ -3820,10 +3905,10 @@ public class WebView extends AbsoluteLayout
private Rect mLastFocusBounds;
// Set by default; BrowserActivity clears to interpret trackball data
- // directly for movement. Currently, the framework only passes
+ // directly for movement. Currently, the framework only passes
// arrow key events, not trackball events, from one child to the next
private boolean mMapTrackballToArrowKeys = true;
-
+
public void setMapTrackballToArrowKeys(boolean setMap) {
mMapTrackballToArrowKeys = setMap;
}
@@ -3841,26 +3926,26 @@ public class WebView extends AbsoluteLayout
return true;
}
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- mPrivateHandler.removeMessages(SWITCH_TO_ENTER);
+ mPrivateHandler.removeMessages(SWITCH_TO_CLICK);
mTrackballDown = true;
if (mNativeClass != 0) {
nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
}
if (time - mLastFocusTime <= TRACKBALL_TIMEOUT
- && !mLastFocusBounds.equals(nativeGetFocusRingBounds())) {
+ && !mLastFocusBounds.equals(nativeGetCursorRingBounds())) {
nativeSelectBestAt(mLastFocusBounds);
}
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "onTrackballEvent down ev=" + ev
- + " time=" + time
+ + " time=" + time
+ " mLastFocusTime=" + mLastFocusTime);
}
if (isInTouchMode()) requestFocusFromTouch();
return false; // let common code in onKeyDown at it
- }
+ }
if (ev.getAction() == MotionEvent.ACTION_UP) {
- // LONG_PRESS_ENTER is set in common onKeyDown
- mPrivateHandler.removeMessages(LONG_PRESS_ENTER);
+ // LONG_PRESS_CENTER is set in common onKeyDown
+ mPrivateHandler.removeMessages(LONG_PRESS_CENTER);
mTrackballDown = false;
mTrackballUpTime = time;
if (mShiftIsPressed) {
@@ -3870,42 +3955,42 @@ public class WebView extends AbsoluteLayout
mExtendSelection = true;
}
}
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "onTrackballEvent up ev=" + ev
- + " time=" + time
+ + " time=" + time
);
}
return false; // let common code in onKeyUp at it
}
if (mMapTrackballToArrowKeys && mShiftIsPressed == false) {
- if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent gmail quit");
+ if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent gmail quit");
return false;
}
- // no move if we're still waiting on SWITCH_TO_ENTER timeout
+ // no move if we're still waiting on SWITCH_TO_CLICK timeout
if (mTouchMode == TOUCH_DOUBLECLICK_MODE) {
- if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent 2 click quit");
+ if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent 2 click quit");
return true;
}
if (mTrackballDown) {
- if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent down quit");
+ if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent down quit");
return true; // discard move if trackball is down
}
if (time - mTrackballUpTime < TRACKBALL_TIMEOUT) {
- if (LOGV_ENABLED) Log.v(LOGTAG, "onTrackballEvent up timeout quit");
+ if (DebugFlags.WEB_VIEW) Log.v(LOGTAG, "onTrackballEvent up timeout quit");
return true;
}
// TODO: alternatively we can do panning as touch does
switchOutDrawHistory();
if (time - mTrackballLastTime > TRACKBALL_TIMEOUT) {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "onTrackballEvent time="
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "onTrackballEvent time="
+ time + " last=" + mTrackballLastTime);
}
mTrackballFirstTime = time;
mTrackballXMove = mTrackballYMove = 0;
}
mTrackballLastTime = time;
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "onTrackballEvent ev=" + ev + " time=" + time);
}
mTrackballRemainsX += ev.getX();
@@ -3913,7 +3998,7 @@ public class WebView extends AbsoluteLayout
doTrackball(time);
return true;
}
-
+
void moveSelection(float xRate, float yRate) {
if (mNativeClass == 0)
return;
@@ -3927,8 +4012,8 @@ public class WebView extends AbsoluteLayout
, mSelectX));
mSelectY = Math.min(maxY, Math.max(mScrollY - SELECT_CURSOR_OFFSET
, mSelectY));
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "moveSelection"
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "moveSelection"
+ " mSelectX=" + mSelectX
+ " mSelectY=" + mSelectY
+ " mScrollX=" + mScrollX
@@ -3940,10 +4025,10 @@ public class WebView extends AbsoluteLayout
nativeMoveSelection(viewToContent(mSelectX)
, viewToContent(mSelectY), mExtendSelection);
int scrollX = mSelectX < mScrollX ? -SELECT_CURSOR_OFFSET
- : mSelectX > maxX - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
+ : mSelectX > maxX - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
: 0;
int scrollY = mSelectY < mScrollY ? -SELECT_CURSOR_OFFSET
- : mSelectY > maxY - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
+ : mSelectY > maxY - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
: 0;
pinScrollBy(scrollX, scrollY, true, 0);
Rect select = new Rect(mSelectX, mSelectY, mSelectX + 1, mSelectY + 1);
@@ -4000,7 +4085,7 @@ public class WebView extends AbsoluteLayout
if (elapsed == 0) {
elapsed = TRACKBALL_TIMEOUT;
}
- float xRate = mTrackballRemainsX * 1000 / elapsed;
+ float xRate = mTrackballRemainsX * 1000 / elapsed;
float yRate = mTrackballRemainsY * 1000 / elapsed;
if (mShiftIsPressed) {
moveSelection(xRate, yRate);
@@ -4010,7 +4095,7 @@ public class WebView extends AbsoluteLayout
float ax = Math.abs(xRate);
float ay = Math.abs(yRate);
float maxA = Math.max(ax, ay);
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "doTrackball elapsed=" + elapsed
+ " xRate=" + xRate
+ " yRate=" + yRate
@@ -4027,9 +4112,9 @@ public class WebView extends AbsoluteLayout
int maxWH = Math.max(width, height);
mZoomScrollX += scaleTrackballX(xRate, maxWH);
mZoomScrollY += scaleTrackballY(yRate, maxWH);
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "doTrackball SCROLL_ZOOM_OUT"
- + " mZoomScrollX=" + mZoomScrollX
+ + " mZoomScrollX=" + mZoomScrollX
+ " mZoomScrollY=" + mZoomScrollY);
}
mZoomScrollX = Math.min(width, Math.max(0, mZoomScrollX));
@@ -4047,13 +4132,13 @@ public class WebView extends AbsoluteLayout
int oldScrollX = mScrollX;
int oldScrollY = mScrollY;
if (count > 0) {
- int selectKeyCode = ax < ay ? mTrackballRemainsY < 0 ?
- KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN :
+ int selectKeyCode = ax < ay ? mTrackballRemainsY < 0 ?
+ KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN :
mTrackballRemainsX < 0 ? KeyEvent.KEYCODE_DPAD_LEFT :
KeyEvent.KEYCODE_DPAD_RIGHT;
count = Math.min(count, TRACKBALL_MOVE_COUNT);
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "doTrackball keyCode=" + selectKeyCode
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "doTrackball keyCode=" + selectKeyCode
+ " count=" + count
+ " mTrackballRemainsX=" + mTrackballRemainsX
+ " mTrackballRemainsY=" + mTrackballRemainsY);
@@ -4066,12 +4151,12 @@ public class WebView extends AbsoluteLayout
if (count >= TRACKBALL_SCROLL_COUNT) {
int xMove = scaleTrackballX(xRate, width);
int yMove = scaleTrackballY(yRate, height);
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "doTrackball pinScrollBy"
+ " count=" + count
+ " xMove=" + xMove + " yMove=" + yMove
- + " mScrollX-oldScrollX=" + (mScrollX-oldScrollX)
- + " mScrollY-oldScrollY=" + (mScrollY-oldScrollY)
+ + " mScrollX-oldScrollX=" + (mScrollX-oldScrollX)
+ + " mScrollY-oldScrollY=" + (mScrollY-oldScrollY)
);
}
if (Math.abs(mScrollX - oldScrollX) > Math.abs(xMove)) {
@@ -4084,18 +4169,18 @@ public class WebView extends AbsoluteLayout
pinScrollBy(xMove, yMove, true, 0);
}
mUserScroll = true;
- }
- mWebViewCore.sendMessage(EventHub.UNBLOCK_FOCUS);
+ }
+ mWebViewCore.sendMessage(EventHub.UNBLOCK_FOCUS);
}
public void flingScroll(int vx, int vy) {
int maxX = Math.max(computeHorizontalScrollRange() - getViewWidth(), 0);
int maxY = Math.max(computeVerticalScrollRange() - getViewHeight(), 0);
-
+
mScroller.fling(mScrollX, mScrollY, vx, vy, 0, maxX, 0, maxY);
invalidate();
}
-
+
private void doFling() {
if (mVelocityTracker == null) {
return;
@@ -4114,7 +4199,7 @@ public class WebView extends AbsoluteLayout
vx = 0;
}
}
-
+
if (true /* EMG release: make our fling more like Maps' */) {
// maps cuts their velocity in half
vx = vx * 3 / 4;
@@ -4175,7 +4260,7 @@ public class WebView extends AbsoluteLayout
}
if (mZoomControls == null) {
mZoomControls = createZoomControls();
-
+
/*
* need to be set to VISIBLE first so that getMeasuredHeight() in
* {@link #onSizeChanged()} can return the measured value for proper
@@ -4184,7 +4269,7 @@ public class WebView extends AbsoluteLayout
mZoomControls.setVisibility(View.VISIBLE);
mZoomControlRunnable = new Runnable() {
public void run() {
-
+
/* Don't dismiss the controls if the user has
* focus on them. Wait and check again later.
*/
@@ -4236,7 +4321,7 @@ public class WebView extends AbsoluteLayout
/**
* Gets the {@link ZoomButtonsController} which can be used to add
* additional buttons to the zoom controls window.
- *
+ *
* @return The instance of {@link ZoomButtonsController} used by this class,
* or null if it is unavailable.
* @hide
@@ -4274,19 +4359,15 @@ public class WebView extends AbsoluteLayout
int contentY = viewToContent((int) mLastTouchY + mScrollY);
Rect rect = new Rect(contentX - mNavSlop, contentY - mNavSlop,
contentX + mNavSlop, contentY + mNavSlop);
- // If we were already focused on a textfield, update its cache.
- if (inEditingMode()) {
- mTextEntry.updateCachedTextfield();
- }
nativeSelectBestAt(rect);
}
/*package*/ void shortPressOnTextField() {
if (inEditingMode()) {
- View v = mTextEntry;
+ View v = mWebTextView;
int x = viewToContent((v.getLeft() + v.getRight()) >> 1);
int y = viewToContent((v.getTop() + v.getBottom()) >> 1);
- nativeMotionUp(x, y, mNavSlop, true);
+ nativeMotionUp(x, y, mNavSlop);
}
}
@@ -4298,14 +4379,13 @@ public class WebView extends AbsoluteLayout
// mLastTouchX and mLastTouchY are the point in the current viewport
int contentX = viewToContent((int) mLastTouchX + mScrollX);
int contentY = viewToContent((int) mLastTouchY + mScrollY);
- if (nativeMotionUp(contentX, contentY, mNavSlop, true)) {
+ if (nativeMotionUp(contentX, contentY, mNavSlop)) {
if (mLogEvent) {
Checkin.updateStats(mContext.getContentResolver(),
Checkin.Stats.Tag.BROWSER_SNAP_CENTER, 1, 0.0);
}
}
- if (nativeUpdateFocusNode() && !mFocusNode.mIsTextField
- && !mFocusNode.mIsTextArea) {
+ if (nativeHasCursorNode() && !nativeCursorIsTextInput()) {
playSoundEffect(SoundEffectConstants.CLICK);
}
}
@@ -4320,7 +4400,8 @@ public class WebView extends AbsoluteLayout
public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
boolean result = false;
if (inEditingMode()) {
- result = mTextEntry.requestFocus(direction, previouslyFocusedRect);
+ result = mWebTextView.requestFocus(direction,
+ previouslyFocusedRect);
} else {
result = super.requestFocus(direction, previouslyFocusedRect);
if (mWebViewCore.getSettings().getNeedInitialFocus()) {
@@ -4344,7 +4425,7 @@ public class WebView extends AbsoluteLayout
default:
return result;
}
- if (mNativeClass != 0 && !nativeUpdateFocusNode()) {
+ if (mNativeClass != 0 && !nativeHasCursorNode()) {
navHandledKey(fakeKeyDirection, 1, true, 0);
}
}
@@ -4413,14 +4494,19 @@ public class WebView extends AbsoluteLayout
int scrollYDelta = 0;
- if (rect.bottom > screenBottom && rect.top > screenTop) {
- if (rect.height() > height) {
- scrollYDelta += (rect.top - screenTop);
+ if (rect.bottom > screenBottom) {
+ int oneThirdOfScreenHeight = height / 3;
+ if (rect.height() > 2 * oneThirdOfScreenHeight) {
+ // If the rectangle is too tall to fit in the bottom two thirds
+ // of the screen, place it at the top.
+ scrollYDelta = rect.top - screenTop;
} else {
- scrollYDelta += (rect.bottom - screenBottom);
+ // If the rectangle will still fit on screen, we want its
+ // top to be in the top third of the screen.
+ scrollYDelta = rect.top - (screenTop + oneThirdOfScreenHeight);
}
} else if (rect.top < screenTop) {
- scrollYDelta -= (screenTop - rect.top);
+ scrollYDelta = rect.top - screenTop;
}
int width = getWidth() - getVerticalScrollbarWidth();
@@ -4445,33 +4531,31 @@ public class WebView extends AbsoluteLayout
return false;
}
-
+
/* package */ void replaceTextfieldText(int oldStart, int oldEnd,
String replace, int newStart, int newEnd) {
HashMap arg = new HashMap();
- arg.put("focusData", new WebViewCore.FocusData(mFocusData));
arg.put("replace", replace);
- arg.put("start", new Integer(newStart));
- arg.put("end", new Integer(newEnd));
+ arg.put("start", Integer.valueOf(newStart));
+ arg.put("end", Integer.valueOf(newEnd));
mTextGeneration++;
mWebViewCore.sendMessage(EventHub.REPLACE_TEXT, oldStart, oldEnd, arg);
}
/* package */ void passToJavaScript(String currentText, KeyEvent event) {
HashMap arg = new HashMap();
- arg.put("focusData", new WebViewCore.FocusData(mFocusData));
arg.put("event", event);
arg.put("currentText", currentText);
// Increase our text generation number, and pass it to webcore thread
mTextGeneration++;
mWebViewCore.sendMessage(EventHub.PASS_TO_JS, mTextGeneration, 0, arg);
// WebKit's document state is not saved until about to leave the page.
- // To make sure the host application, like Browser, has the up to date
- // document state when it goes to background, we force to save the
+ // To make sure the host application, like Browser, has the up to date
+ // document state when it goes to background, we force to save the
// document state.
mWebViewCore.removeMessages(EventHub.SAVE_DOCUMENT_STATE);
mWebViewCore.sendMessageDelayed(EventHub.SAVE_DOCUMENT_STATE,
- new WebViewCore.FocusData(mFocusData), 1000);
+ cursorData(), 1000);
}
/* package */ WebViewCore getWebViewCore() {
@@ -4489,9 +4573,9 @@ public class WebView extends AbsoluteLayout
class PrivateHandler extends Handler {
@Override
public void handleMessage(Message msg) {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, msg.what < REMEMBER_PASSWORD || msg.what
- > INVAL_RECT_MSG_ID ? Integer.toString(msg.what)
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, msg.what < REMEMBER_PASSWORD || msg.what
+ > INVAL_RECT_MSG_ID ? Integer.toString(msg.what)
: HandlerDebugString[msg.what - REMEMBER_PASSWORD]);
}
switch (msg.what) {
@@ -4519,22 +4603,31 @@ public class WebView extends AbsoluteLayout
case SWITCH_TO_LONGPRESS: {
mTouchMode = TOUCH_DONE_MODE;
performLongClick();
- updateTextEntry();
+ rebuildWebTextView();
break;
}
- case SWITCH_TO_ENTER:
- if (LOGV_ENABLED) Log.v(LOGTAG, "SWITCH_TO_ENTER");
+ case SWITCH_TO_CLICK:
mTouchMode = TOUCH_DONE_MODE;
- onKeyUp(KeyEvent.KEYCODE_ENTER
- , new KeyEvent(KeyEvent.ACTION_UP
- , KeyEvent.KEYCODE_ENTER));
+ Rect visibleRect = sendOurVisibleRect();
+ // Note that sendOurVisibleRect calls viewToContent, so the
+ // coordinates should be in content coordinates.
+ if (!nativeCursorIntersects(visibleRect)) {
+ break;
+ }
+ nativeSetFollowedLink(true);
+ mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE,
+ cursorData());
+ playSoundEffect(SoundEffectConstants.CLICK);
+ if (!mCallbackProxy.uiOverrideUrlLoading(nativeCursorText())) {
+ mWebViewCore.sendMessage(EventHub.CLICK);
+ }
break;
case SCROLL_BY_MSG_ID:
setContentScrollBy(msg.arg1, msg.arg2, (Boolean) msg.obj);
break;
case SYNC_SCROLL_TO_MSG_ID:
if (mUserScroll) {
- // if user has scrolled explicitly, don't sync the
+ // if user has scrolled explicitly, don't sync the
// scroll position any more
mUserScroll = false;
break;
@@ -4543,7 +4636,7 @@ public class WebView extends AbsoluteLayout
case SCROLL_TO_MSG_ID:
if (setContentScrollTo(msg.arg1, msg.arg2)) {
// if we can't scroll to the exact position due to pin,
- // send a message to WebCore to re-scroll when we get a
+ // send a message to WebCore to re-scroll when we get a
// new picture
mUserScroll = false;
mWebViewCore.sendMessage(EventHub.SYNC_SCROLL,
@@ -4555,7 +4648,7 @@ public class WebView extends AbsoluteLayout
break;
case NEW_PICTURE_MSG_ID:
// called for new content
- final WebViewCore.DrawData draw =
+ final WebViewCore.DrawData draw =
(WebViewCore.DrawData) msg.obj;
final Point viewSize = draw.mViewPoint;
if (mZoomScale > 0) {
@@ -4578,9 +4671,9 @@ public class WebView extends AbsoluteLayout
// received in the fixed dimension.
final boolean updateLayout = viewSize.x == mLastWidthSent
&& viewSize.y == mLastHeightSent;
- recordNewContentSize(draw.mWidthHeight.x,
+ recordNewContentSize(draw.mWidthHeight.x,
draw.mWidthHeight.y, updateLayout);
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Rect b = draw.mInvalRegion.getBounds();
Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" +
b.left+","+b.top+","+b.right+","+b.bottom+"}");
@@ -4596,22 +4689,23 @@ public class WebView extends AbsoluteLayout
break;
case UPDATE_TEXTFIELD_TEXT_MSG_ID:
// Make sure that the textfield is currently focused
- // and representing the same node as the pointer.
- if (inEditingMode() &&
- mTextEntry.isSameTextField(msg.arg1)) {
+ // and representing the same node as the pointer.
+ if (inEditingMode() &&
+ mWebTextView.isSameTextField(msg.arg1)) {
if (msg.getData().getBoolean("password")) {
- Spannable text = (Spannable) mTextEntry.getText();
+ Spannable text = (Spannable) mWebTextView.getText();
int start = Selection.getSelectionStart(text);
int end = Selection.getSelectionEnd(text);
- mTextEntry.setInPassword(true);
+ mWebTextView.setInPassword(true);
// Restore the selection, which may have been
// ruined by setInPassword.
- Spannable pword = (Spannable) mTextEntry.getText();
+ Spannable pword =
+ (Spannable) mWebTextView.getText();
Selection.setSelection(pword, start, end);
// If the text entry has created more events, ignore
// this one.
} else if (msg.arg2 == mTextGeneration) {
- mTextEntry.setTextAndKeepSelection(
+ mWebTextView.setTextAndKeepSelection(
(String) msg.obj);
}
}
@@ -4621,7 +4715,7 @@ public class WebView extends AbsoluteLayout
break;
}
// Do not reset the focus or clear the text; the user may have already
-// navigated or entered text at this point. The focus should have gotten
+// navigated or entered text at this point. The focus should have gotten
// reset, if need be, when the focus cache was built. Similarly, the text
// view should already be torn down and rebuilt if needed.
// nativeResetFocus();
@@ -4656,6 +4750,7 @@ public class WebView extends AbsoluteLayout
if (mInitialScale > 0) {
scale = mInitialScale / 100.0f;
} else {
+ if (initialScale < 0) break;
if (mWebViewCore.getSettings().getUseWideViewPort()) {
// force viewSizeChanged by setting mLastWidthSent
// to 0
@@ -4676,22 +4771,13 @@ public class WebView extends AbsoluteLayout
case MARK_NODE_INVALID_ID:
nativeMarkNodeInvalid(msg.arg1);
break;
- case NOTIFY_FOCUS_SET_MSG_ID:
- if (mNativeClass != 0) {
- nativeNotifyFocusSet(inEditingMode());
- }
- break;
case UPDATE_TEXT_ENTRY_MSG_ID:
- // this is sent after finishing resize in WebViewCore. Make
+ // this is sent after finishing resize in WebViewCore. Make
// sure the text edit box is still on the screen.
- boolean alreadyThere = inEditingMode();
- if (alreadyThere && nativeUpdateFocusNode()) {
- FocusNode node = mFocusNode;
- if (node.mIsTextField || node.mIsTextArea) {
- mTextEntry.bringIntoView();
- }
+ if (inEditingMode() && nativeCursorIsTextInput()) {
+ mWebTextView.bringIntoView();
}
- updateTextEntry();
+ rebuildWebTextView();
break;
case RECOMPUTE_FOCUS_MSG_ID:
if (mNativeClass != 0) {
@@ -4709,17 +4795,17 @@ public class WebView extends AbsoluteLayout
}
break;
}
- case UPDATE_TEXT_ENTRY_ADAPTER:
+ case REQUEST_FORM_DATA:
HashMap data = (HashMap) msg.obj;
- if (mTextEntry.isSameTextField(msg.arg1)) {
+ if (mWebTextView.isSameTextField(msg.arg1)) {
AutoCompleteAdapter adapter =
(AutoCompleteAdapter) data.get("adapter");
- mTextEntry.setAdapterCustom(adapter);
+ mWebTextView.setAdapterCustom(adapter);
}
break;
case UPDATE_CLIPBOARD:
String str = (String) msg.obj;
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "UPDATE_CLIPBOARD " + str);
}
try {
@@ -4734,12 +4820,12 @@ public class WebView extends AbsoluteLayout
WebViewCore.resumeUpdate(mWebViewCore);
break;
- case LONG_PRESS_ENTER:
+ case LONG_PRESS_CENTER:
// as this is shared by keydown and trackballdown, reset all
// the states
- mGotEnterDown = false;
+ mGotCenterDown = false;
mTrackballDown = false;
- // LONG_PRESS_ENTER is sent as a delayed message. If we
+ // LONG_PRESS_CENTER is sent as a delayed message. If we
// switch to windows overview, the WebView will be
// temporarily removed from the view system. In that case,
// do nothing.
@@ -4770,16 +4856,12 @@ public class WebView extends AbsoluteLayout
// Class used to use a dropdown for a <select> element
private class InvokeListBox implements Runnable {
- // Strings for the labels in the listbox.
- private String[] mArray;
- // Array representing whether each item is enabled.
- private boolean[] mEnableArray;
// Whether the listbox allows multiple selection.
private boolean mMultiple;
// Passed in to a list with multiple selection to tell
// which items are selected.
private int[] mSelectedArray;
- // Passed in to a list with single selection to tell
+ // Passed in to a list with single selection to tell
// where the initial selection is.
private int mSelection;
@@ -4798,14 +4880,14 @@ public class WebView extends AbsoluteLayout
}
/**
- * Subclass ArrayAdapter so we can disable OptionGroupLabels,
+ * Subclass ArrayAdapter so we can disable OptionGroupLabels,
* and allow filtering.
*/
private class MyArrayListAdapter extends ArrayAdapter<Container> {
public MyArrayListAdapter(Context context, Container[] objects, boolean multiple) {
- super(context,
+ super(context,
multiple ? com.android.internal.R.layout.select_dialog_multichoice :
- com.android.internal.R.layout.select_dialog_singlechoice,
+ com.android.internal.R.layout.select_dialog_singlechoice,
objects);
}
@@ -4863,7 +4945,7 @@ public class WebView extends AbsoluteLayout
}
}
- private InvokeListBox(String[] array, boolean[] enabled, int
+ private InvokeListBox(String[] array, boolean[] enabled, int
selection) {
mSelection = selection;
mMultiple = false;
@@ -4926,31 +5008,36 @@ public class WebView extends AbsoluteLayout
public void run() {
final ListView listView = (ListView) LayoutInflater.from(mContext)
.inflate(com.android.internal.R.layout.select_dialog, null);
- final MyArrayListAdapter adapter = new
+ final MyArrayListAdapter adapter = new
MyArrayListAdapter(mContext, mContainers, mMultiple);
AlertDialog.Builder b = new AlertDialog.Builder(mContext)
.setView(listView).setCancelable(true)
.setInverseBackgroundForced(true);
-
+
if (mMultiple) {
b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
mWebViewCore.sendMessage(
- EventHub.LISTBOX_CHOICES,
+ EventHub.LISTBOX_CHOICES,
adapter.getCount(), 0,
listView.getCheckedItemPositions());
}});
- b.setNegativeButton(android.R.string.cancel, null);
+ b.setNegativeButton(android.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ mWebViewCore.sendMessage(
+ EventHub.SINGLE_LISTBOX_CHOICE, -2, 0);
+ }});
}
final AlertDialog dialog = b.create();
listView.setAdapter(adapter);
listView.setFocusableInTouchMode(true);
// There is a bug (1250103) where the checks in a ListView with
// multiple items selected are associated with the positions, not
- // the ids, so the items do not properly retain their checks when
+ // the ids, so the items do not properly retain their checks when
// filtered. Do not allow filtering on multiple lists until
// that bug is fixed.
-
+
listView.setTextFilterEnabled(!mMultiple);
if (mMultiple) {
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
@@ -5013,48 +5100,26 @@ public class WebView extends AbsoluteLayout
}
// called by JNI
- private void sendFinalFocus(int frame, int node, int x, int y) {
- WebViewCore.FocusData focusData = new WebViewCore.FocusData();
- focusData.mFrame = frame;
- focusData.mNode = node;
- focusData.mX = x;
- focusData.mY = y;
- mWebViewCore.sendMessage(EventHub.SET_FINAL_FOCUS,
- EventHub.NO_FOCUS_CHANGE_BLOCK, 0, focusData);
+ private void sendMoveMouse(int frame, int node, int x, int y) {
+ mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE,
+ new WebViewCore.CursorData(frame, node, x, y));
}
// called by JNI
- private void setFocusData(int moveGeneration, int buildGeneration,
- int frame, int node, int x, int y, boolean ignoreNullFocus) {
- mFocusData.mMoveGeneration = moveGeneration;
- mFocusData.mBuildGeneration = buildGeneration;
- mFocusData.mFrame = frame;
- mFocusData.mNode = node;
- mFocusData.mX = x;
- mFocusData.mY = y;
- mFocusData.mIgnoreNullFocus = ignoreNullFocus;
- }
-
- // called by JNI
- private void sendKitFocus() {
- WebViewCore.FocusData focusData = new WebViewCore.FocusData(mFocusData);
- mWebViewCore.sendMessage(EventHub.SET_KIT_FOCUS, focusData);
+ private void sendMoveMouseIfLatest() {
+ mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE_IF_LATEST, cursorData());
}
// called by JNI
- private void sendMotionUp(int touchGeneration, int buildGeneration,
- int frame, int node, int x, int y, int size, boolean isClick,
- boolean retry) {
+ private void sendMotionUp(int touchGeneration,
+ int frame, int node, int x, int y, int size) {
WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData();
touchUpData.mMoveGeneration = touchGeneration;
- touchUpData.mBuildGeneration = buildGeneration;
touchUpData.mSize = size;
- touchUpData.mIsClick = isClick;
- touchUpData.mRetry = retry;
- mFocusData.mFrame = touchUpData.mFrame = frame;
- mFocusData.mNode = touchUpData.mNode = node;
- mFocusData.mX = touchUpData.mX = x;
- mFocusData.mY = touchUpData.mY = y;
+ touchUpData.mFrame = frame;
+ touchUpData.mNode = node;
+ touchUpData.mX = x;
+ touchUpData.mY = y;
mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData);
}
@@ -5093,7 +5158,7 @@ public class WebView extends AbsoluteLayout
private void viewInvalidate() {
invalidate();
}
-
+
// return true if the key was handled
private boolean navHandledKey(int keyCode, int count, boolean noScroll
, long time) {
@@ -5101,9 +5166,9 @@ public class WebView extends AbsoluteLayout
return false;
}
mLastFocusTime = time;
- mLastFocusBounds = nativeGetFocusRingBounds();
+ mLastFocusBounds = nativeGetCursorRingBounds();
boolean keyHandled = nativeMoveFocus(keyCode, count, noScroll) == false;
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "navHandledKey mLastFocusBounds=" + mLastFocusBounds
+ " mLastFocusTime=" + mLastFocusTime
+ " handled=" + keyHandled);
@@ -5111,7 +5176,7 @@ public class WebView extends AbsoluteLayout
if (keyHandled == false || mHeightCanMeasure == false) {
return keyHandled;
}
- Rect contentFocus = nativeGetFocusRingBounds();
+ Rect contentFocus = nativeGetCursorRingBounds();
if (contentFocus.isEmpty()) return keyHandled;
Rect viewFocus = contentToView(contentFocus);
Rect visRect = new Rect();
@@ -5135,14 +5200,14 @@ public class WebView extends AbsoluteLayout
}
if (mLastFocusBounds.isEmpty()) return keyHandled;
if (mLastFocusBounds.equals(contentFocus)) return keyHandled;
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "navHandledKey contentFocus=" + contentFocus);
}
requestRectangleOnScreen(viewFocus);
mUserScroll = true;
return keyHandled;
}
-
+
/**
* Set the background color. It's white by default. Pass
* zero to make the view transparent.
@@ -5157,7 +5222,7 @@ public class WebView extends AbsoluteLayout
nativeDebugDump();
mWebViewCore.sendMessage(EventHub.DUMP_NAVTREE);
}
-
+
/**
* Update our cache with updatedText.
* @param updatedText The new text to put in our cache.
@@ -5167,52 +5232,70 @@ public class WebView extends AbsoluteLayout
// we recognize that it is up to date.
nativeUpdateCachedTextfield(updatedText, mTextGeneration);
}
-
- // Never call this version except by updateCachedTextfield(String) -
- // we always want to pass in our generation number.
- private native void nativeUpdateCachedTextfield(String updatedText,
- int generation);
+
private native void nativeClearFocus(int x, int y);
private native void nativeCreate(int ptr);
+ private native int nativeCursorFramePointer();
+ private native Rect nativeCursorNodeBounds();
+ /* package */ native int nativeCursorNodePointer();
+ /* package */ native boolean nativeCursorMatchesFocus();
+ private native boolean nativeCursorIntersects(Rect visibleRect);
+ private native boolean nativeCursorIsAnchor();
+ private native boolean nativeCursorIsTextInput();
+ private native String nativeCursorText();
+ private native boolean nativeCursorWantsKeyEvents();
private native void nativeDebugDump();
private native void nativeDestroy();
- private native void nativeDrawFocusRing(Canvas content);
+ private native void nativeDrawCursorRing(Canvas content);
+ private native void nativeDrawMatches(Canvas canvas);
private native void nativeDrawSelection(Canvas content
, int x, int y, boolean extendSelection);
private native void nativeDrawSelectionRegion(Canvas content);
- private native boolean nativeUpdateFocusNode();
- private native Rect nativeGetFocusRingBounds();
- private native Rect nativeGetNavBounds();
+ private native void nativeDumpDisplayTree(String urlOrNull);
+ private native int nativeFindAll(String findLower, String findUpper);
+ private native void nativeFindNext(boolean forward);
+ private native boolean nativeFocusIsPassword();
+ private native boolean nativeFocusIsRtlText();
+ private native boolean nativeFocusIsTextField();
+ private native boolean nativeFocusIsTextInput();
+ private native int nativeFocusMaxLength();
+ private native String nativeFocusName();
+ private native Rect nativeFocusNodeBounds();
+ /* package */ native int nativeFocusNodePointer();
+ private native String nativeFocusText();
+ private native int nativeFocusTextSize();
+ /**
+ * Returns true if the native focus nodes says it wants to handle key events
+ * (ala plugins). This can only be called if mNativeClass is non-zero!
+ */
+ private native Rect nativeGetCursorRingBounds();
+ private native Region nativeGetSelection();
+ private native boolean nativeHasCursorNode();
+ private native boolean nativeHasFocusNode();
+ private native String nativeImageURI(int x, int y);
private native void nativeInstrumentReport();
private native void nativeMarkNodeInvalid(int node);
// return true if the page has been scrolled
- private native boolean nativeMotionUp(int x, int y, int slop, boolean isClick);
+ private native boolean nativeMotionUp(int x, int y, int slop);
// returns false if it handled the key
- private native boolean nativeMoveFocus(int keyCode, int count,
+ private native boolean nativeMoveFocus(int keyCode, int count,
boolean noScroll);
- private native void nativeNotifyFocusSet(boolean inEditingMode);
+ private native int nativeMoveGeneration();
+ private native void nativeMoveSelection(int x, int y,
+ boolean extendSelection);
private native void nativeRecomputeFocus();
// Like many other of our native methods, you must make sure that
// mNativeClass is not null before calling this method.
private native void nativeRecordButtons(boolean focused,
boolean pressed, boolean invalidate);
- private native void nativeResetFocus();
- private native void nativeResetNavClipBounds();
private native void nativeSelectBestAt(Rect rect);
private native void nativeSetFindIsDown();
private native void nativeSetFollowedLink(boolean followed);
private native void nativeSetHeightCanMeasure(boolean measure);
- private native void nativeSetNavBounds(Rect rect);
- private native void nativeSetNavClipBounds(Rect rect);
- private native String nativeImageURI(int x, int y);
- /**
- * Returns true if the native focus nodes says it wants to handle key events
- * (ala plugins). This can only be called if mNativeClass is non-zero!
- */
- private native boolean nativeFocusNodeWantsKeyEvents();
- private native void nativeMoveSelection(int x, int y
- , boolean extendSelection);
- private native Region nativeGetSelection();
+ private native int nativeTextGeneration();
+ // Never call this version except by updateCachedTextfield(String) -
+ // we always want to pass in our generation number.
+ private native void nativeUpdateCachedTextfield(String updatedText,
+ int generation);
- private native void nativeDumpDisplayTree(String urlOrNull);
}
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index e9df453..f4b99b9 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -41,8 +41,6 @@ import junit.framework.Assert;
final class WebViewCore {
private static final String LOGTAG = "webcore";
- static final boolean DEBUG = false;
- static final boolean LOGV_ENABLED = DEBUG;
static {
// Load libwebcore during static initialization. This happens in the
@@ -96,7 +94,7 @@ final class WebViewCore {
private int mViewportMaximumScale = 0;
private boolean mViewportUserScalable = true;
-
+
private int mRestoredScale = 100;
private int mRestoredX = 0;
private int mRestoredY = 0;
@@ -143,6 +141,8 @@ final class WebViewCore {
// The WebIconDatabase needs to be initialized within the UI thread so
// just request the instance here.
WebIconDatabase.getInstance();
+ // Create the WebStorage singleton
+ WebStorage.getInstance();
// Send a message to initialize the WebViewCore.
Message init = sWebCoreHandler.obtainMessage(
WebCoreThread.INITIALIZE, this);
@@ -162,6 +162,8 @@ final class WebViewCore {
mSettings.syncSettingsAndCreateHandler(mBrowserFrame);
// Create the handler and transfer messages for the IconDatabase
WebIconDatabase.getInstance().createHandler();
+ // Create the handler for WebStorage
+ WebStorage.getInstance().createHandler();
// The transferMessages call will transfer all pending messages to the
// WebCore thread handler.
mEventHub.transferMessages();
@@ -225,6 +227,16 @@ final class WebViewCore {
}
/**
+ * Add an error message to the client's console.
+ * @param message The message to add
+ * @param lineNumber the line on which the error occurred
+ * @param sourceID the filename of the source that caused the error.
+ */
+ protected void addMessageToConsole(String message, int lineNumber, String sourceID) {
+ mCallbackProxy.addMessageToConsole(message, lineNumber, sourceID);
+ }
+
+ /**
* Invoke a javascript alert.
* @param message The message displayed in the alert.
*/
@@ -233,6 +245,27 @@ final class WebViewCore {
}
/**
+ * Notify the user that the origin has exceeded it's database quota.
+ * @param url The URL that caused the overflow.
+ * @param databaseIdentifier The identifier of the database.
+ * @param currentQuota The current quota for the origin.
+ */
+ protected void exceededDatabaseQuota(String url,
+ String databaseIdentifier,
+ long currentQuota) {
+ // Inform the callback proxy of the quota overflow. Send an object
+ // that encapsulates a call to the nativeSetDatabaseQuota method to
+ // awaken the sleeping webcore thread when a decision from the
+ // client to allow or deny quota is available.
+ mCallbackProxy.onExceededDatabaseQuota(url, databaseIdentifier,
+ currentQuota, new WebStorage.QuotaUpdater() {
+ public void updateQuota(long quota) {
+ nativeSetDatabaseQuota(quota);
+ }
+ });
+ }
+
+ /**
* Invoke a javascript confirm dialog.
* @param message The message displayed in the dialog.
* @return True if the user confirmed or false if the user cancelled.
@@ -283,25 +316,30 @@ final class WebViewCore {
* Empty the picture set.
*/
private native void nativeClearContent();
-
+
/**
* Create a flat picture from the set of pictures.
*/
private native void nativeCopyContentToPicture(Picture picture);
-
+
/**
* Draw the picture set with a background color. Returns true
- * if some individual picture took too long to draw and can be
+ * if some individual picture took too long to draw and can be
* split into parts. Called from the UI thread.
*/
private native boolean nativeDrawContent(Canvas canvas, int color);
-
+
+ /**
+ * check to see if picture is blank and in progress
+ */
+ private native boolean nativePictureReady();
+
/**
* Redraw a portion of the picture set. The Point wh returns the
* width and height of the overall picture.
*/
private native boolean nativeRecordContent(Region invalRegion, Point wh);
-
+
/**
* Splits slow parts of the picture set. Called from the webkit
* thread after nativeDrawContent returns true.
@@ -329,60 +367,58 @@ final class WebViewCore {
float scale, int realScreenWidth, int screenHeight);
private native int nativeGetContentMinPrefWidth();
-
+
// Start: functions that deal with text editing
- private native void nativeReplaceTextfieldText(int frame, int node, int x,
- int y, int oldStart, int oldEnd, String replace, int newStart,
- int newEnd);
+ private native void nativeReplaceTextfieldText(
+ int oldStart, int oldEnd, String replace, int newStart, int newEnd);
- private native void passToJs(int frame, int node, int x, int y, int gen,
+ private native void passToJs(int gen,
String currentText, int keyCode, int keyValue, boolean down,
boolean cap, boolean fn, boolean sym);
+ private native void nativeSetFocusControllerActive(boolean active);
+
private native void nativeSaveDocumentState(int frame);
- private native void nativeSetFinalFocus(int framePtr, int nodePtr, int x,
- int y, boolean block);
+ private native void nativeMoveMouse(int framePtr, int nodePtr, int x,
+ int y);
- private native void nativeSetKitFocus(int moveGeneration,
- int buildGeneration, int framePtr, int nodePtr, int x, int y,
+ private native void nativeMoveMouseIfLatest(int moveGeneration,
+ int framePtr, int nodePtr, int x, int y,
boolean ignoreNullFocus);
private native String nativeRetrieveHref(int framePtr, int nodePtr);
-
- private native void nativeTouchUp(int touchGeneration,
- int buildGeneration, int framePtr, int nodePtr, int x, int y,
- int size, boolean isClick, boolean retry);
+
+ private native void nativeTouchUp(int touchGeneration,
+ int framePtr, int nodePtr, int x, int y,
+ int size);
private native boolean nativeHandleTouchEvent(int action, int x, int y);
private native void nativeUnblockFocus();
-
+
private native void nativeUpdateFrameCache();
-
+
private native void nativeSetSnapAnchor(int x, int y);
-
+
private native void nativeSnapToAnchor();
-
+
private native void nativeSetBackgroundColor(int color);
-
+
private native void nativeDumpDomTree(boolean useFile);
private native void nativeDumpRenderTree(boolean useFile);
private native void nativeDumpNavTree();
- private native void nativeRefreshPlugins(boolean reloadOpenPages);
-
/**
* Delete text from start to end in the focused textfield. If there is no
- * focus, or if start == end, silently fail. If start and end are out of
+ * focus, or if start == end, silently fail. If start and end are out of
* order, swap them.
* @param start Beginning of selection to delete.
* @param end End of selection to delete.
*/
- private native void nativeDeleteSelection(int frame, int node, int x, int y,
- int start, int end);
+ private native void nativeDeleteSelection(int start, int end);
/**
* Set the selection to (start, end) in the focused textfield. If start and
@@ -390,15 +426,22 @@ final class WebViewCore {
* @param start Beginning of selection.
* @param end End of selection.
*/
- private native void nativeSetSelection(int frame, int node, int x, int y,
- int start, int end);
+ private native void nativeSetSelection(int start, int end);
private native String nativeGetSelection(Region sel);
-
+
// Register a scheme to be treated as local scheme so that it can access
// local asset files for resources
private native void nativeRegisterURLSchemeAsLocal(String scheme);
+ /*
+ * Inform webcore that the user has decided whether to allow or deny new
+ * quota for the current origin and that the main thread should wake up
+ * now.
+ * @param quota The new quota.
+ */
+ private native void nativeSetDatabaseQuota(long quota);
+
// EventHub for processing messages
private final EventHub mEventHub;
// WebCore thread handler
@@ -447,7 +490,7 @@ final class WebViewCore {
CacheManager.endCacheTransaction();
CacheManager.startCacheTransaction();
sendMessageDelayed(
- obtainMessage(CACHE_TICKER),
+ obtainMessage(CACHE_TICKER),
CACHE_TICKER_INTERVAL);
}
break;
@@ -472,19 +515,15 @@ final class WebViewCore {
}
}
- static class FocusData {
- FocusData() {}
- FocusData(FocusData d) {
- mMoveGeneration = d.mMoveGeneration;
- mBuildGeneration = d.mBuildGeneration;
- mFrame = d.mFrame;
- mNode = d.mNode;
- mX = d.mX;
- mY = d.mY;
- mIgnoreNullFocus = d.mIgnoreNullFocus;
+ static class CursorData {
+ CursorData() {}
+ CursorData(int frame, int node, int x, int y) {
+ mFrame = frame;
+ mNode = node;
+ mX = x;
+ mY = y;
}
int mMoveGeneration;
- int mBuildGeneration;
int mFrame;
int mNode;
int mX;
@@ -494,14 +533,11 @@ final class WebViewCore {
static class TouchUpData {
int mMoveGeneration;
- int mBuildGeneration;
int mFrame;
int mNode;
int mX;
int mY;
int mSize;
- boolean mIsClick;
- boolean mRetry;
}
static class TouchEventData {
@@ -536,23 +572,26 @@ final class WebViewCore {
"DELETE_SELECTION", // = 122;
"LISTBOX_CHOICES", // = 123;
"SINGLE_LISTBOX_CHOICE", // = 124;
- "125",
+ "MESSAGE_RELAY", // = 125;
"SET_BACKGROUND_COLOR", // = 126;
"UNBLOCK_FOCUS", // = 127;
"SAVE_DOCUMENT_STATE", // = 128;
"GET_SELECTION", // = 129;
"WEBKIT_DRAW", // = 130;
"SYNC_SCROLL", // = 131;
- "REFRESH_PLUGINS", // = 132;
+ "POST_URL", // = 132;
"SPLIT_PICTURE_SET", // = 133;
"CLEAR_CONTENT", // = 134;
- "SET_FINAL_FOCUS", // = 135;
- "SET_KIT_FOCUS", // = 136;
+ "SET_MOVE_MOUSE", // = 135;
+ "SET_MOVE_MOUSE_IF_LATEST", // = 136;
"REQUEST_FOCUS_HREF", // = 137;
"ADD_JS_INTERFACE", // = 138;
"LOAD_DATA", // = 139;
"TOUCH_UP", // = 140;
"TOUCH_EVENT", // = 141;
+ "SET_ACTIVE", // = 142;
+ "ON_PAUSE", // = 143
+ "ON_RESUME", // = 144
};
class EventHub {
@@ -582,19 +621,20 @@ final class WebViewCore {
static final int DELETE_SELECTION = 122;
static final int LISTBOX_CHOICES = 123;
static final int SINGLE_LISTBOX_CHOICE = 124;
+ static final int MESSAGE_RELAY = 125;
static final int SET_BACKGROUND_COLOR = 126;
static final int UNBLOCK_FOCUS = 127;
static final int SAVE_DOCUMENT_STATE = 128;
static final int GET_SELECTION = 129;
static final int WEBKIT_DRAW = 130;
static final int SYNC_SCROLL = 131;
- static final int REFRESH_PLUGINS = 132;
+ static final int POST_URL = 132;
static final int SPLIT_PICTURE_SET = 133;
static final int CLEAR_CONTENT = 134;
-
+
// UI nav messages
- static final int SET_FINAL_FOCUS = 135;
- static final int SET_KIT_FOCUS = 136;
+ static final int SET_MOVE_MOUSE = 135;
+ static final int SET_MOVE_MOUSE_IF_LATEST = 136;
static final int REQUEST_FOCUS_HREF = 137;
static final int ADD_JS_INTERFACE = 138;
static final int LOAD_DATA = 139;
@@ -604,6 +644,15 @@ final class WebViewCore {
// message used to pass UI touch events to WebCore
static final int TOUCH_EVENT = 141;
+ // Used to tell the focus controller whether to draw the blinking cursor
+ // or not, based on whether the WebView has focus.
+ static final int SET_ACTIVE = 142;
+
+ // pause/resume activity for just this DOM (unlike pauseTimers, which
+ // is global)
+ static final int ON_PAUSE = 143;
+ static final int ON_RESUME = 144;
+
// Network-based messaging
static final int CLEAR_SSL_PREF_TABLE = 150;
@@ -618,10 +667,6 @@ final class WebViewCore {
// private message ids
private static final int DESTROY = 200;
-
- // flag values passed to message SET_FINAL_FOCUS
- static final int NO_FOCUS_CHANGE_BLOCK = 0;
- static final int BLOCK_FOCUS_CHANGE_UNTIL_KEY_UP = 1;
// Private handler for WebCore messages.
private Handler mHandler;
@@ -650,9 +695,9 @@ final class WebViewCore {
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, msg.what < LOAD_URL || msg.what
- > TOUCH_EVENT ? Integer.toString(msg.what)
+ if (DebugFlags.WEB_VIEW_CORE) {
+ Log.v(LOGTAG, msg.what < LOAD_URL || msg.what
+ > SET_ACTIVE ? Integer.toString(msg.what)
: HandlerDebugString[msg.what - LOAD_URL]);
}
switch (msg.what) {
@@ -672,6 +717,13 @@ final class WebViewCore {
loadUrl((String) msg.obj);
break;
+ case POST_URL: {
+ HashMap param = (HashMap) msg.obj;
+ String url = (String) param.get("url");
+ byte[] data = (byte[]) param.get("data");
+ mBrowserFrame.postUrl(url, data);
+ break;
+ }
case LOAD_DATA:
HashMap loadParams = (HashMap) msg.obj;
String baseUrl = (String) loadParams.get("baseUrl");
@@ -687,7 +739,7 @@ final class WebViewCore {
* we automatically add the scheme of the
* baseUrl for local access as long as it is
* not http(s)/ftp(s)/about/javascript
- */
+ */
String scheme = baseUrl.substring(0, i);
if (!scheme.startsWith("http") &&
!scheme.startsWith("ftp") &&
@@ -705,9 +757,9 @@ final class WebViewCore {
break;
case STOP_LOADING:
- // If the WebCore has committed the load, but not
- // finished the first layout yet, we need to set
- // first layout done to trigger the interpreted side sync
+ // If the WebCore has committed the load, but not
+ // finished the first layout yet, we need to set
+ // first layout done to trigger the interpreted side sync
// up with native side
if (mBrowserFrame.committed()
&& !mBrowserFrame.firstLayoutDone()) {
@@ -743,7 +795,7 @@ final class WebViewCore {
// (inv-zoom)
nativeSetScrollOffset(msg.arg1, msg.arg2);
break;
-
+
case SET_GLOBAL_BOUNDS:
Rect r = (Rect) msg.obj;
nativeSetGlobalBounds(r.left, r.top, r.width(),
@@ -754,7 +806,7 @@ final class WebViewCore {
// If it is a standard load and the load is not
// committed yet, we interpret BACK as RELOAD
if (!mBrowserFrame.committed() && msg.arg1 == -1 &&
- (mBrowserFrame.loadType() ==
+ (mBrowserFrame.loadType() ==
BrowserFrame.FRAME_LOADTYPE_STANDARD)) {
mBrowserFrame.reload(true);
} else {
@@ -791,6 +843,14 @@ final class WebViewCore {
}
break;
+ case ON_PAUSE:
+ nativePause();
+ break;
+
+ case ON_RESUME:
+ nativeResume();
+ break;
+
case SET_NETWORK_STATE:
if (BrowserFrame.sJavaBridge == null) {
throw new IllegalStateException("No WebView " +
@@ -812,28 +872,24 @@ final class WebViewCore {
close(mBrowserFrame.mNativeFrame);
break;
- case REPLACE_TEXT:
+ case REPLACE_TEXT:
HashMap jMap = (HashMap) msg.obj;
- FocusData fData = (FocusData) jMap.get("focusData");
String replace = (String) jMap.get("replace");
- int newStart =
+ int newStart =
((Integer) jMap.get("start")).intValue();
- int newEnd =
+ int newEnd =
((Integer) jMap.get("end")).intValue();
- nativeReplaceTextfieldText(fData.mFrame,
- fData.mNode, fData.mX, fData.mY, msg.arg1,
+ nativeReplaceTextfieldText(msg.arg1,
msg.arg2, replace, newStart, newEnd);
break;
case PASS_TO_JS: {
HashMap jsMap = (HashMap) msg.obj;
- FocusData fDat = (FocusData) jsMap.get("focusData");
KeyEvent evt = (KeyEvent) jsMap.get("event");
int keyCode = evt.getKeyCode();
int keyValue = evt.getUnicodeChar();
int generation = msg.arg1;
- passToJs(fDat.mFrame, fDat.mNode, fDat.mX, fDat.mY,
- generation,
+ passToJs(generation,
(String) jsMap.get("currentText"),
keyCode,
keyValue,
@@ -844,7 +900,7 @@ final class WebViewCore {
}
case SAVE_DOCUMENT_STATE: {
- FocusData fDat = (FocusData) msg.obj;
+ CursorData fDat = (CursorData) msg.obj;
nativeSaveDocumentState(fDat.mFrame);
break;
}
@@ -857,11 +913,9 @@ final class WebViewCore {
case TOUCH_UP:
TouchUpData touchUpData = (TouchUpData) msg.obj;
nativeTouchUp(touchUpData.mMoveGeneration,
- touchUpData.mBuildGeneration,
touchUpData.mFrame, touchUpData.mNode,
- touchUpData.mX, touchUpData.mY,
- touchUpData.mSize, touchUpData.mIsClick,
- touchUpData.mRetry);
+ touchUpData.mX, touchUpData.mY,
+ touchUpData.mSize);
break;
case TOUCH_EVENT: {
@@ -874,6 +928,10 @@ final class WebViewCore {
break;
}
+ case SET_ACTIVE:
+ nativeSetFocusControllerActive(msg.arg1 == 1);
+ break;
+
case ADD_JS_INTERFACE:
HashMap map = (HashMap) msg.obj;
Object obj = map.get("object");
@@ -892,22 +950,20 @@ final class WebViewCore {
mBrowserFrame.documentAsText((Message) msg.obj);
break;
- case SET_FINAL_FOCUS:
- FocusData finalData = (FocusData) msg.obj;
- nativeSetFinalFocus(finalData.mFrame,
- finalData.mNode, finalData.mX,
- finalData.mY, msg.arg1
- != EventHub.NO_FOCUS_CHANGE_BLOCK);
+ case SET_MOVE_MOUSE:
+ CursorData finalData = (CursorData) msg.obj;
+ nativeMoveMouse(finalData.mFrame,
+ finalData.mNode, finalData.mX,
+ finalData.mY);
break;
case UNBLOCK_FOCUS:
nativeUnblockFocus();
break;
- case SET_KIT_FOCUS:
- FocusData focusData = (FocusData) msg.obj;
- nativeSetKitFocus(focusData.mMoveGeneration,
- focusData.mBuildGeneration,
+ case SET_MOVE_MOUSE_IF_LATEST:
+ CursorData focusData = (CursorData) msg.obj;
+ nativeMoveMouseIfLatest(focusData.mMoveGeneration,
focusData.mFrame, focusData.mNode,
focusData.mX, focusData.mY,
focusData.mIgnoreNullFocus);
@@ -920,7 +976,7 @@ final class WebViewCore {
hrefMsg.sendToTarget();
break;
}
-
+
case UPDATE_CACHE_AND_TEXT_ENTRY:
nativeUpdateFrameCache();
// FIXME: this should provide a minimal rectangle
@@ -940,21 +996,15 @@ final class WebViewCore {
case SET_SNAP_ANCHOR:
nativeSetSnapAnchor(msg.arg1, msg.arg2);
break;
-
+
case DELETE_SELECTION:
- FocusData delData = (FocusData) msg.obj;
- nativeDeleteSelection(delData.mFrame,
- delData.mNode, delData.mX,
- delData.mY, msg.arg1, msg.arg2);
+ nativeDeleteSelection(msg.arg1, msg.arg2);
break;
case SET_SELECTION:
- FocusData selData = (FocusData) msg.obj;
- nativeSetSelection(selData.mFrame,
- selData.mNode, selData.mX,
- selData.mY, msg.arg1, msg.arg2);
+ nativeSetSelection(msg.arg1, msg.arg2);
break;
-
+
case LISTBOX_CHOICES:
SparseBooleanArray choices = (SparseBooleanArray)
msg.obj;
@@ -963,18 +1013,18 @@ final class WebViewCore {
for (int c = 0; c < choicesSize; c++) {
choicesArray[c] = choices.get(c);
}
- nativeSendListBoxChoices(choicesArray,
+ nativeSendListBoxChoices(choicesArray,
choicesSize);
break;
case SINGLE_LISTBOX_CHOICE:
nativeSendListBoxChoice(msg.arg1);
break;
-
+
case SET_BACKGROUND_COLOR:
nativeSetBackgroundColor(msg.arg1);
break;
-
+
case GET_SELECTION:
String str = nativeGetSelection((Region) msg.obj);
Message.obtain(mWebView.mPrivateHandler
@@ -999,21 +1049,23 @@ final class WebViewCore {
mWebkitScrollY = msg.arg2;
break;
- case REFRESH_PLUGINS:
- nativeRefreshPlugins(msg.arg1 != 0);
- break;
-
case SPLIT_PICTURE_SET:
nativeSplitContent();
mSplitPictureIsScheduled = false;
break;
-
+
case CLEAR_CONTENT:
// Clear the view so that onDraw() will draw nothing
// but white background
// (See public method WebView.clearView)
nativeClearContent();
break;
+
+ case MESSAGE_RELAY:
+ if (msg.obj instanceof Message) {
+ ((Message) msg.obj).sendToTarget();
+ }
+ break;
}
}
};
@@ -1103,7 +1155,7 @@ final class WebViewCore {
//-------------------------------------------------------------------------
void stopLoading() {
- if (LOGV_ENABLED) Log.v(LOGTAG, "CORE stopLoading");
+ if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "CORE stopLoading");
if (mBrowserFrame != null) {
mBrowserFrame.stopLoading();
}
@@ -1179,19 +1231,22 @@ final class WebViewCore {
//-------------------------------------------------------------------------
private void loadUrl(String url) {
- if (LOGV_ENABLED) Log.v(LOGTAG, " CORE loadUrl " + url);
+ if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, " CORE loadUrl " + url);
mBrowserFrame.loadUrl(url);
}
private void key(KeyEvent evt, boolean isDown) {
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW_CORE) {
Log.v(LOGTAG, "CORE key at " + System.currentTimeMillis() + ", "
+ evt);
}
- if (!nativeKey(evt.getKeyCode(), evt.getUnicodeChar(),
+ int keyCode = evt.getKeyCode();
+ if (!nativeKey(keyCode, evt.getUnicodeChar(),
evt.getRepeatCount(), evt.isShiftPressed(), evt.isAltPressed(),
- isDown)) {
+ isDown) && keyCode != KeyEvent.KEYCODE_ENTER) {
// bubble up the event handling
+ // but do not bubble up the ENTER key, which would open the search
+ // bar without any text.
mCallbackProxy.onUnhandledKeyEvent(evt);
}
}
@@ -1202,7 +1257,7 @@ final class WebViewCore {
// notify webkit that our virtual view size changed size (after inv-zoom)
private void viewSizeChanged(int w, int h, float scale) {
- if (LOGV_ENABLED) Log.v(LOGTAG, "CORE onSizeChanged");
+ if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "CORE onSizeChanged");
if (w == 0) {
Log.w(LOGTAG, "skip viewSizeChanged as w is 0");
return;
@@ -1211,7 +1266,7 @@ final class WebViewCore {
&& (w < mViewportWidth || mViewportWidth == -1)) {
int width = mViewportWidth;
if (mViewportWidth == -1) {
- if (mSettings.getLayoutAlgorithm() ==
+ if (mSettings.getLayoutAlgorithm() ==
WebSettings.LayoutAlgorithm.NORMAL) {
width = WebView.ZOOM_OUT_WIDTH;
} else {
@@ -1242,7 +1297,7 @@ final class WebViewCore {
if (needInvalidate) {
// ensure {@link #webkitDraw} is called as we were blocking in
// {@link #contentDraw} when mCurrentViewWidth is 0
- if (LOGV_ENABLED) Log.v(LOGTAG, "viewSizeChanged");
+ if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "viewSizeChanged");
contentDraw();
}
mEventHub.sendMessage(Message.obtain(null,
@@ -1258,7 +1313,7 @@ final class WebViewCore {
// Used to avoid posting more than one draw message.
private boolean mDrawIsScheduled;
-
+
// Used to avoid posting more than one split picture message.
private boolean mSplitPictureIsScheduled;
@@ -1267,7 +1322,7 @@ final class WebViewCore {
// Used to end scale+scroll mode, accessed by both threads
boolean mEndScaleZoom = false;
-
+
public class DrawData {
public DrawData() {
mInvalRegion = new Region();
@@ -1277,21 +1332,21 @@ final class WebViewCore {
public Point mViewPoint;
public Point mWidthHeight;
}
-
+
private void webkitDraw() {
mDrawIsScheduled = false;
DrawData draw = new DrawData();
- if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw start");
- if (nativeRecordContent(draw.mInvalRegion, draw.mWidthHeight)
+ if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw start");
+ if (nativeRecordContent(draw.mInvalRegion, draw.mWidthHeight)
== false) {
- if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw abort");
+ if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw abort");
return;
}
if (mWebView != null) {
// Send the native view size that was used during the most recent
// layout.
draw.mViewPoint = new Point(mCurrentViewWidth, mCurrentViewHeight);
- if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID");
+ if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID");
Message.obtain(mWebView.mPrivateHandler,
WebView.NEW_PICTURE_MSG_ID, draw).sendToTarget();
if (mWebkitScrollX != 0 || mWebkitScrollY != 0) {
@@ -1339,6 +1394,10 @@ final class WebViewCore {
}
}
+ /* package */ boolean pictureReady() {
+ return nativePictureReady();
+ }
+
/*package*/ Picture copyContentPicture() {
Picture result = new Picture();
nativeCopyContentToPicture(result);
@@ -1352,9 +1411,9 @@ final class WebViewCore {
sWebCoreHandler.sendMessageAtFrontOfQueue(sWebCoreHandler
.obtainMessage(WebCoreThread.REDUCE_PRIORITY));
// Note: there is one possible failure mode. If pauseUpdate() is called
- // from UI thread while in webcore thread WEBKIT_DRAW is just pulled out
- // of the queue and about to be executed. mDrawIsScheduled may be set to
- // false in webkitDraw(). So update won't be blocked. But at least the
+ // from UI thread while in webcore thread WEBKIT_DRAW is just pulled out
+ // of the queue and about to be executed. mDrawIsScheduled may be set to
+ // false in webkitDraw(). So update won't be blocked. But at least the
// webcore thread priority is still lowered.
if (core != null) {
synchronized (core) {
@@ -1374,7 +1433,7 @@ final class WebViewCore {
synchronized (core) {
core.mDrawIsScheduled = false;
core.mDrawIsPaused = false;
- if (LOGV_ENABLED) Log.v(LOGTAG, "resumeUpdate");
+ if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "resumeUpdate");
core.contentDraw();
}
}
@@ -1423,7 +1482,7 @@ final class WebViewCore {
mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW));
}
}
-
+
// called by JNI
private void contentScrollBy(int dx, int dy, boolean animate) {
if (!mBrowserFrame.firstLayoutDone()) {
@@ -1431,9 +1490,14 @@ final class WebViewCore {
return;
}
if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.SCROLL_BY_MSG_ID, dx, dy,
- new Boolean(animate)).sendToTarget();
+ Message msg = Message.obtain(mWebView.mPrivateHandler,
+ WebView.SCROLL_BY_MSG_ID, dx, dy, new Boolean(animate));
+ if (mDrawIsScheduled) {
+ mEventHub.sendMessage(Message.obtain(null,
+ EventHub.MESSAGE_RELAY, msg));
+ } else {
+ msg.sendToTarget();
+ }
}
}
@@ -1450,8 +1514,14 @@ final class WebViewCore {
return;
}
if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.SCROLL_TO_MSG_ID, x, y).sendToTarget();
+ Message msg = Message.obtain(mWebView.mPrivateHandler,
+ WebView.SCROLL_TO_MSG_ID, x, y);
+ if (mDrawIsScheduled) {
+ mEventHub.sendMessage(Message.obtain(null,
+ EventHub.MESSAGE_RELAY, msg));
+ } else {
+ msg.sendToTarget();
+ }
}
}
@@ -1468,8 +1538,14 @@ final class WebViewCore {
return;
}
if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.SPAWN_SCROLL_TO_MSG_ID, x, y).sendToTarget();
+ Message msg = Message.obtain(mWebView.mPrivateHandler,
+ WebView.SPAWN_SCROLL_TO_MSG_ID, x, y);
+ if (mDrawIsScheduled) {
+ mEventHub.sendMessage(Message.obtain(null,
+ EventHub.MESSAGE_RELAY, msg));
+ } else {
+ msg.sendToTarget();
+ }
}
}
@@ -1482,14 +1558,6 @@ final class WebViewCore {
}
// called by JNI
- private void sendNotifyFocusSet() {
- if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.NOTIFY_FOCUS_SET_MSG_ID).sendToTarget();
- }
- }
-
- // called by JNI
private void sendNotifyProgressFinished() {
sendUpdateTextEntry();
// as CacheManager can behave based on database transaction, we need to
@@ -1525,12 +1593,12 @@ final class WebViewCore {
}
private native void setViewportSettingsFromNative();
-
+
// called by JNI
- private void didFirstLayout() {
+ private void didFirstLayout(boolean standardLoad) {
// Trick to ensure that the Picture has the exact height for the content
// by forcing to layout with 0 height after the page is ready, which is
- // indicated by didFirstLayout. This is essential to get rid of the
+ // indicated by didFirstLayout. This is essential to get rid of the
// white space in the GMail which uses WebView for message view.
if (mWebView != null && mWebView.mHeightCanMeasure) {
mWebView.mLastHeightSent = 0;
@@ -1575,7 +1643,7 @@ final class WebViewCore {
mViewportMaximumScale = mViewportInitialScale;
} else if (mViewportInitialScale == 0) {
mViewportInitialScale = mViewportMaximumScale;
- }
+ }
}
if (mViewportWidth < 0 && mViewportInitialScale == 100) {
mViewportWidth = 0;
@@ -1593,16 +1661,14 @@ final class WebViewCore {
scaleLimit).sendToTarget();
mRestoredScale = 0;
} else {
+ // if standardLoad is true, use mViewportInitialScale, otherwise
+ // pass -1 to the WebView to indicate no change of the scale.
Message.obtain(mWebView.mPrivateHandler,
- WebView.DID_FIRST_LAYOUT_MSG_ID, mViewportInitialScale,
+ WebView.DID_FIRST_LAYOUT_MSG_ID,
+ standardLoad ? mViewportInitialScale : -1,
mViewportWidth, scaleLimit).sendToTarget();
}
- // if no restored offset, move the new page to (0, 0)
- Message.obtain(mWebView.mPrivateHandler, WebView.SCROLL_TO_MSG_ID,
- mRestoredX, mRestoredY).sendToTarget();
- mRestoredX = mRestoredY = 0;
-
// force an early draw for quick feedback after the first layout
if (mCurrentViewWidth != 0) {
synchronized (this) {
@@ -1610,10 +1676,19 @@ final class WebViewCore {
mEventHub.removeMessages(EventHub.WEBKIT_DRAW);
}
mDrawIsScheduled = true;
+ // if no restored offset, move the new page to (0, 0)
+ mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
+ EventHub.MESSAGE_RELAY, Message.obtain(
+ mWebView.mPrivateHandler,
+ WebView.SCROLL_TO_MSG_ID, mRestoredX,
+ mRestoredY)));
mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
EventHub.WEBKIT_DRAW));
}
}
+
+ // reset restored offset
+ mRestoredX = mRestoredY = 0;
}
}
@@ -1638,7 +1713,7 @@ final class WebViewCore {
String text, int textGeneration) {
if (mWebView != null) {
Message msg = Message.obtain(mWebView.mPrivateHandler,
- WebView.UPDATE_TEXTFIELD_TEXT_MSG_ID, ptr,
+ WebView.UPDATE_TEXTFIELD_TEXT_MSG_ID, ptr,
textGeneration, text);
msg.getData().putBoolean("password", changeToPassword);
msg.sendToTarget();
@@ -1664,6 +1739,9 @@ final class WebViewCore {
if (mWebView != null) {
mWebView.requestListBox(array, enabledArray, selection);
}
-
+
}
+
+ private native void nativePause();
+ private native void nativeResume();
}
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 04cb8a0..f92eb99 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -320,11 +320,6 @@ public abstract class AbsSeekBar extends ProgressBar {
final int max = getMax();
progress += scale * max;
- if (progress < 0) {
- progress = 0;
- } else if (progress > max) {
- progress = max;
- }
setProgress((int) progress, true);
}
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 7d2fcbc..fe6d91a 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -163,7 +163,7 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
/**
* View to show if there are no items to show.
*/
- View mEmptyView;
+ private View mEmptyView;
/**
* The number of items in the current adapter.
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index 32e5504..c28210d 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -348,12 +348,7 @@ public class ArrayAdapter<T> extends BaseAdapter implements Filterable {
"ArrayAdapter requires the resource ID to be a TextView", e);
}
- T item = getItem(position);
- if (item instanceof CharSequence) {
- text.setText((CharSequence)item);
- } else {
- text.setText(item.toString());
- }
+ text.setText(getItem(position).toString());
return view;
}
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index a1d16ea..bfc5f08 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -126,7 +126,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
// Indicates whether this AutoCompleteTextView is attached to a window or not
// The widget is attached to a window when mAttachCount > 0
private int mAttachCount;
-
+
private AutoCompleteTextView.PassThroughClickListener mPassThroughClickListener;
public AutoCompleteTextView(Context context) {
@@ -188,7 +188,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
setFocusable(true);
addTextChangedListener(new MyWatcher());
-
+
mPassThroughClickListener = new PassThroughClickListener();
super.setOnClickListener(mPassThroughClickListener);
}
@@ -290,8 +290,6 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
* @return the background drawable
*
* @attr ref android.R.styleable#PopupWindow_popupBackground
- *
- * @hide Pending API council approval
*/
public Drawable getDropDownBackground() {
return mPopup.getBackground();
@@ -303,8 +301,6 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
* @param d the drawable to set as the background
*
* @attr ref android.R.styleable#PopupWindow_popupBackground
- *
- * @hide Pending API council approval
*/
public void setDropDownBackgroundDrawable(Drawable d) {
mPopup.setBackgroundDrawable(d);
@@ -316,47 +312,15 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
* @param id the id of the drawable to set as the background
*
* @attr ref android.R.styleable#PopupWindow_popupBackground
- *
- * @hide Pending API council approval
*/
public void setDropDownBackgroundResource(int id) {
mPopup.setBackgroundDrawable(getResources().getDrawable(id));
}
-
- /**
- * <p>Sets the animation style of the auto-complete drop-down list.</p>
- *
- * <p>If the drop-down is showing, calling this method will take effect only
- * the next time the drop-down is shown.</p>
- *
- * @param animationStyle animation style to use when the drop-down appears
- * and disappears. Set to -1 for the default animation, 0 for no
- * animation, or a resource identifier for an explicit animation.
- *
- * @hide Pending API council approval
- */
- public void setDropDownAnimationStyle(int animationStyle) {
- mPopup.setAnimationStyle(animationStyle);
- }
-
- /**
- * <p>Returns the animation style that is used when the drop-down list appears and disappears
- * </p>
- *
- * @return the animation style that is used when the drop-down list appears and disappears
- *
- * @hide Pending API council approval
- */
- public int getDropDownAnimationStyle() {
- return mPopup.getAnimationStyle();
- }
/**
* <p>Sets the vertical offset used for the auto-complete drop-down list.</p>
*
* @param offset the vertical offset
- *
- * @hide Pending API council approval
*/
public void setDropDownVerticalOffset(int offset) {
mDropDownVerticalOffset = offset;
@@ -366,8 +330,6 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
* <p>Gets the vertical offset used for the auto-complete drop-down list.</p>
*
* @return the vertical offset
- *
- * @hide Pending API council approval
*/
public int getDropDownVerticalOffset() {
return mDropDownVerticalOffset;
@@ -377,8 +339,6 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
* <p>Sets the horizontal offset used for the auto-complete drop-down list.</p>
*
* @param offset the horizontal offset
- *
- * @hide Pending API council approval
*/
public void setDropDownHorizontalOffset(int offset) {
mDropDownHorizontalOffset = offset;
@@ -388,13 +348,39 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
* <p>Gets the horizontal offset used for the auto-complete drop-down list.</p>
*
* @return the horizontal offset
- *
- * @hide Pending API council approval
*/
public int getDropDownHorizontalOffset() {
return mDropDownHorizontalOffset;
}
+ /**
+ * <p>Sets the animation style of the auto-complete drop-down list.</p>
+ *
+ * <p>If the drop-down is showing, calling this method will take effect only
+ * the next time the drop-down is shown.</p>
+ *
+ * @param animationStyle animation style to use when the drop-down appears
+ * and disappears. Set to -1 for the default animation, 0 for no
+ * animation, or a resource identifier for an explicit animation.
+ *
+ * @hide Pending API council approval
+ */
+ public void setDropDownAnimationStyle(int animationStyle) {
+ mPopup.setAnimationStyle(animationStyle);
+ }
+
+ /**
+ * <p>Returns the animation style that is used when the drop-down list appears and disappears
+ * </p>
+ *
+ * @return the animation style that is used when the drop-down list appears and disappears
+ *
+ * @hide Pending API council approval
+ */
+ public int getDropDownAnimationStyle() {
+ return mPopup.getAnimationStyle();
+ }
+
/**
* @return Whether the drop-down is visible as long as there is {@link #enoughToFilter()}
*
@@ -1074,10 +1060,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
}
mPopup.setHeight(height);
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
-
- // use outside touchable to dismiss drop down when touching outside of it, so
- // only set this if the dropdown is not always visible
- mPopup.setOutsideTouchable(!mDropDownAlwaysVisible);
+ mPopup.setOutsideTouchable(true);
mPopup.setTouchInterceptor(new PopupTouchIntercepter());
mPopup.showAsDropDown(getDropDownAnchorView(),
mDropDownHorizontalOffset, mDropDownVerticalOffset);
@@ -1399,7 +1382,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
*/
CharSequence fixText(CharSequence invalidText);
}
-
+
/**
* Allows us a private hook into the on click event without preventing users from setting
* their own click listener.
@@ -1415,5 +1398,5 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
if (mWrapped != null) mWrapped.onClick(v);
}
}
-
+
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index ac8b589..fa2bb22 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -93,7 +93,26 @@ public class ZygoteInit {
/** Controls whether we should preload resources during zygote init. */
private static final boolean PRELOAD_RESOURCES = true;
-
+
+ /**
+ * List of methods we "warm up" in the register map cache. These were
+ * chosen because they appeared on the stack in GCs in multiple
+ * applications.
+ *
+ * This is in a VM-ready format, to minimize string processing. If a
+ * class is not already loaded, or a method is not found, the entry
+ * will be skipped.
+ *
+ * This doesn't really merit a separately-generated input file at this
+ * time. The list is fairly short, and the consequences of failure
+ * are minor.
+ */
+ private static final String[] REGISTER_MAP_METHODS = {
+ // (currently not doing any)
+ //"Landroid/app/Activity;.setContentView:(I)V",
+ };
+
+
/**
* Invokes a static "main(argv[]) method on class "className".
* Converts various failing exceptions into RuntimeExceptions, with
@@ -319,6 +338,45 @@ public class ZygoteInit {
}
/**
+ * Pre-caches register maps for methods that are commonly used.
+ */
+ private static void cacheRegisterMaps() {
+ String failed = null;
+ int failure;
+ long startTime = System.nanoTime();
+
+ failure = 0;
+
+ for (int i = 0; i < REGISTER_MAP_METHODS.length; i++) {
+ String str = REGISTER_MAP_METHODS[i];
+
+ if (!Debug.cacheRegisterMap(str)) {
+ if (failed == null)
+ failed = str;
+ failure++;
+ }
+ }
+
+ long delta = System.nanoTime() - startTime;
+
+ if (failure == REGISTER_MAP_METHODS.length) {
+ if (REGISTER_MAP_METHODS.length > 0) {
+ Log.i(TAG,
+ "Register map caching failed (precise GC not enabled?)");
+ }
+ return;
+ }
+
+ Log.i(TAG, "Register map cache: found " +
+ (REGISTER_MAP_METHODS.length - failure) + " of " +
+ REGISTER_MAP_METHODS.length + " methods in " +
+ (delta / 1000000L) + "ms");
+ if (failure > 0) {
+ Log.i(TAG, " First failure: " + failed);
+ }
+ }
+
+ /**
* Load in commonly used resources, so they can be shared across
* processes.
*
@@ -510,6 +568,7 @@ public class ZygoteInit {
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preloadClasses();
+ //cacheRegisterMaps();
preloadResources();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
diff --git a/core/java/com/google/android/mms/pdu/EncodedStringValue.java b/core/java/com/google/android/mms/pdu/EncodedStringValue.java
index 7696c5e..a27962d 100644
--- a/core/java/com/google/android/mms/pdu/EncodedStringValue.java
+++ b/core/java/com/google/android/mms/pdu/EncodedStringValue.java
@@ -269,4 +269,16 @@ public class EncodedStringValue implements Cloneable {
return new EncodedStringValue(value.mCharacterSet, value.mData);
}
+
+ public static EncodedStringValue[] encodeStrings(String[] array) {
+ int count = array.length;
+ if (count > 0) {
+ EncodedStringValue[] encodedArray = new EncodedStringValue[count];
+ for (int i = 0; i < count; i++) {
+ encodedArray[i] = new EncodedStringValue(array[i]);
+ }
+ return encodedArray;
+ }
+ return null;
+ }
}
diff --git a/core/jni/ActivityManager.cpp b/core/jni/ActivityManager.cpp
index 9017827..8950dfb 100644
--- a/core/jni/ActivityManager.cpp
+++ b/core/jni/ActivityManager.cpp
@@ -16,9 +16,9 @@
#include <unistd.h>
#include <android_runtime/ActivityManager.h>
-#include <utils/IBinder.h>
-#include <utils/IServiceManager.h>
-#include <utils/Parcel.h>
+#include <binder/IBinder.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
#include <utils/String8.h>
namespace android {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index ed8deb1..31cc4f7 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -38,7 +38,6 @@ LOCAL_SRC_FILES:= \
android_text_AndroidCharacter.cpp \
android_text_KeyCharacterMap.cpp \
android_os_Debug.cpp \
- android_os_Exec.cpp \
android_os_FileUtils.cpp \
android_os_MemoryFile.cpp \
android_os_ParcelFileDescriptor.cpp \
@@ -103,11 +102,10 @@ LOCAL_SRC_FILES:= \
android_util_FileObserver.cpp \
android/opengl/poly_clip.cpp.arm \
android/opengl/util.cpp.arm \
- android_bluetooth_Database.cpp \
android_bluetooth_HeadsetBase.cpp \
android_bluetooth_common.cpp \
android_bluetooth_BluetoothAudioGateway.cpp \
- android_bluetooth_RfcommSocket.cpp \
+ android_bluetooth_BluetoothSocket.cpp \
android_bluetooth_ScoSocket.cpp \
android_server_BluetoothDeviceService.cpp \
android_server_BluetoothEventLoop.cpp \
@@ -147,6 +145,7 @@ LOCAL_SHARED_LIBRARIES := \
libnativehelper \
libcutils \
libutils \
+ libbinder \
libnetutils \
libui \
libskiagl \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 302f39e..6de37f0 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -19,12 +19,12 @@
//#define LOG_NDEBUG 0
#include <android_runtime/AndroidRuntime.h>
-#include <utils/IBinder.h>
-#include <utils/IServiceManager.h>
+#include <binder/IBinder.h>
+#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <utils/misc.h>
-#include <utils/Parcel.h>
-#include <utils/string_array.h>
+#include <binder/Parcel.h>
+#include <utils/StringArray.h>
#include <utils/threads.h>
#include <cutils/properties.h>
@@ -130,7 +130,6 @@ extern int register_android_os_Power(JNIEnv *env);
extern int register_android_os_StatFs(JNIEnv *env);
extern int register_android_os_SystemProperties(JNIEnv *env);
extern int register_android_os_Hardware(JNIEnv* env);
-extern int register_android_os_Exec(JNIEnv *env);
extern int register_android_os_SystemClock(JNIEnv* env);
extern int register_android_os_FileObserver(JNIEnv *env);
extern int register_android_os_FileUtils(JNIEnv *env);
@@ -143,10 +142,9 @@ extern int register_android_security_Md5MessageDigest(JNIEnv *env);
extern int register_android_text_AndroidCharacter(JNIEnv *env);
extern int register_android_text_KeyCharacterMap(JNIEnv *env);
extern int register_android_opengl_classes(JNIEnv *env);
-extern int register_android_bluetooth_Database(JNIEnv* env);
extern int register_android_bluetooth_HeadsetBase(JNIEnv* env);
extern int register_android_bluetooth_BluetoothAudioGateway(JNIEnv* env);
-extern int register_android_bluetooth_RfcommSocket(JNIEnv *env);
+extern int register_android_bluetooth_BluetoothSocket(JNIEnv *env);
extern int register_android_bluetooth_ScoSocket(JNIEnv *env);
extern int register_android_server_BluetoothDeviceService(JNIEnv* env);
extern int register_android_server_BluetoothEventLoop(JNIEnv *env);
@@ -507,11 +505,17 @@ static void readLocale(char* language, char* region)
//LOGD("language=%s region=%s\n", language, region);
}
-void AndroidRuntime::start(const char* className, const bool startSystemServer)
+/*
+ * Start the Dalvik Virtual Machine.
+ *
+ * Various arguments, most determined by system properties, are passed in.
+ * The "mOptions" vector is updated.
+ *
+ * Returns 0 on success.
+ */
+int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
{
- LOGD("\n>>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<\n");
-
- JNIEnv* env;
+ int result = -1;
JavaVMInitArgs initArgs;
JavaVMOption opt;
char propBuf[PROPERTY_VALUE_MAX];
@@ -520,24 +524,11 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX];
char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
char* stackTraceFile = NULL;
- char* slashClassName = NULL;
- char* cp;
bool checkJni = false;
+ bool checkDexSum = false;
bool logStdio = false;
enum { kEMDefault, kEMIntPortable, kEMIntFast } executionMode = kEMDefault;
- blockSigpipe();
-
- /*
- * 'startSystemServer == true' means runtime is obslete 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,
- ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
- }
property_get("dalvik.vm.checkjni", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
@@ -559,6 +550,11 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
property_get("dalvik.vm.stack-trace-file", stackTraceFileBuf, "");
+ property_get("dalvik.vm.check-dex-sum", propBuf, "");
+ if (strcmp(propBuf, "true") == 0) {
+ checkDexSum = true;
+ }
+
property_get("log.redirect-stdio", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
logStdio = true;
@@ -570,19 +566,6 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
strcpy(jniOptsBuf, "-Xjniopts:");
property_get("dalvik.vm.jniopts", jniOptsBuf+10, "");
- const char* rootDir = getenv("ANDROID_ROOT");
- if (rootDir == NULL) {
- rootDir = "/system";
- if (!hasDir("/system")) {
- LOG_FATAL("No root directory specified, and /android does not exist.");
- return;
- }
- setenv("ANDROID_ROOT", rootDir, 1);
- }
-
- const char* kernelHack = getenv("LD_ASSUME_KERNEL");
- //LOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
-
/* route exit() to our handler */
opt.extraInfo = (void*) runtime_exit;
opt.optionString = "exit";
@@ -656,6 +639,10 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
if (opc != NULL) {
opt.optionString = "-Xgenregmap";
mOptions.add(opt);
+
+ /* turn on precise GC while we're at it */
+ opt.optionString = "-Xgc:precise";
+ mOptions.add(opt);
}
}
@@ -702,6 +689,13 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
opt.optionString = "-Xint:fast";
mOptions.add(opt);
}
+
+ if (checkDexSum) {
+ /* perform additional DEX checksum tests */
+ opt.optionString = "-Xcheckdexsum";
+ mOptions.add(opt);
+ }
+
if (logStdio) {
/* convert stdout/stderr to log messages */
opt.optionString = "-Xlog-stdio";
@@ -769,11 +763,61 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
* If this call succeeds, the VM is ready, and we can start issuing
* JNI calls.
*/
- if (JNI_CreateJavaVM(&mJavaVM, &env, &initArgs) < 0) {
+ if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
LOGE("JNI_CreateJavaVM failed\n");
goto bail;
}
+ result = 0;
+
+bail:
+ free(stackTraceFile);
+ return result;
+}
+
+/*
+ * Start the Android runtime. This involves starting the virtual machine
+ * and calling the "static void main(String[] args)" method in the class
+ * named by "className".
+ */
+void AndroidRuntime::start(const char* className, const bool startSystemServer)
+{
+ LOGD("\n>>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<\n");
+
+ char* slashClassName = NULL;
+ char* cp;
+ JNIEnv* env;
+
+ blockSigpipe();
+
+ /*
+ * 'startSystemServer == true' means runtime is obslete 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,
+ ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
+ }
+
+ const char* rootDir = getenv("ANDROID_ROOT");
+ if (rootDir == NULL) {
+ rootDir = "/system";
+ if (!hasDir("/system")) {
+ LOG_FATAL("No root directory specified, and /android does not exist.");
+ goto bail;
+ }
+ setenv("ANDROID_ROOT", rootDir, 1);
+ }
+
+ //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
+ //LOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
+
+ /* start the virtual machine */
+ if (startVm(&mJavaVM, &env) != 0)
+ goto bail;
+
/*
* Register android functions.
*/
@@ -843,7 +887,6 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
bail:
free(slashClassName);
- free(stackTraceFile);
}
void AndroidRuntime::start()
@@ -1093,7 +1136,6 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_database_SQLiteQuery),
REG_JNI(register_android_database_SQLiteStatement),
REG_JNI(register_android_os_Debug),
- REG_JNI(register_android_os_Exec),
REG_JNI(register_android_os_FileObserver),
REG_JNI(register_android_os_FileUtils),
REG_JNI(register_android_os_ParcelFileDescriptor),
@@ -1115,10 +1157,9 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_media_ToneGenerator),
REG_JNI(register_android_opengl_classes),
- REG_JNI(register_android_bluetooth_Database),
REG_JNI(register_android_bluetooth_HeadsetBase),
REG_JNI(register_android_bluetooth_BluetoothAudioGateway),
- REG_JNI(register_android_bluetooth_RfcommSocket),
+ REG_JNI(register_android_bluetooth_BluetoothSocket),
REG_JNI(register_android_bluetooth_ScoSocket),
REG_JNI(register_android_server_BluetoothDeviceService),
REG_JNI(register_android_server_BluetoothEventLoop),
diff --git a/core/jni/CursorWindow.cpp b/core/jni/CursorWindow.cpp
index fb891c9..7864189 100644
--- a/core/jni/CursorWindow.cpp
+++ b/core/jni/CursorWindow.cpp
@@ -18,7 +18,7 @@
#define LOG_TAG "CursorWindow"
#include <utils/Log.h>
-#include <utils/MemoryDealer.h>
+#include <binder/MemoryDealer.h>
#include <assert.h>
#include <string.h>
diff --git a/core/jni/CursorWindow.h b/core/jni/CursorWindow.h
index 0fb074f..e98b009 100644
--- a/core/jni/CursorWindow.h
+++ b/core/jni/CursorWindow.h
@@ -21,7 +21,7 @@
#include <stddef.h>
#include <stdint.h>
-#include <utils/MemoryDealer.h>
+#include <binder/MemoryDealer.h>
#include <utils/RefBase.h>
#include <jni.h>
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 65f44d5..29d8d3c 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -5,7 +5,7 @@
#include "SkDither.h"
#include "SkUnPreMultiply.h"
-#include "Parcel.h"
+#include <binder/Parcel.h>
#include "android_util_Binder.h"
#include "android_nio_utils.h"
#include "CreateJavaOutputStreamAdaptor.h"
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index effb1c8..11c608c 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -75,9 +75,8 @@ public:
return result;
}
- static void computeBounds(JNIEnv* env, jobject clazz, SkPath* obj, jobject bounds, SkPath::BoundsType btype) {
- SkRect bounds_;
- obj->computeBounds(&bounds_, btype);
+ static void computeBounds(JNIEnv* env, jobject clazz, SkPath* obj, jobject bounds, int boundstype) {
+ const SkRect& bounds_ = obj->getBounds();
GraphicsJNI::rect_to_jrectf(bounds_, env, bounds);
}
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index 1dc0314..723cd37 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -134,7 +134,7 @@ static void Region_scale(JNIEnv* env, jobject region, jfloat scale, jobject dst)
////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#include "Parcel.h"
+#include <binder/Parcel.h>
#include "android_util_Binder.h"
static SkRegion* Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel)
diff --git a/core/jni/android_bluetooth_BluetoothSocket.cpp b/core/jni/android_bluetooth_BluetoothSocket.cpp
new file mode 100644
index 0000000..9c4f7c7
--- /dev/null
+++ b/core/jni/android_bluetooth_BluetoothSocket.cpp
@@ -0,0 +1,517 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BluetoothSocket.cpp"
+
+#include "android_bluetooth_common.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "JNIHelp.h"
+#include "utils/Log.h"
+#include "cutils/abort_socket.h"
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#ifdef HAVE_BLUETOOTH
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/sco.h>
+#endif
+
+#define TYPE_AS_STR(t) \
+ ((t) == TYPE_RFCOMM ? "RFCOMM" : ((t) == TYPE_SCO ? "SCO" : "L2CAP"))
+
+namespace android {
+
+static jfieldID field_mAuth; /* read-only */
+static jfieldID field_mEncrypt; /* read-only */
+static jfieldID field_mType; /* read-only */
+static jfieldID field_mAddress; /* read-only */
+static jfieldID field_mPort; /* read-only */
+static jfieldID field_mSocketData;
+static jmethodID method_BluetoothSocket_ctor;
+static jclass class_BluetoothSocket;
+
+/* Keep TYPE_RFCOMM etc in sync with BluetoothSocket.java */
+static const int TYPE_RFCOMM = 1;
+static const int TYPE_SCO = 2;
+static const int TYPE_L2CAP = 3; // TODO: Test l2cap code paths
+
+static struct asocket *get_socketData(JNIEnv *env, jobject obj) {
+ struct asocket *s =
+ (struct asocket *) env->GetIntField(obj, field_mSocketData);
+ if (!s)
+ jniThrowException(env, "java/io/IOException", "null socketData");
+ return s;
+}
+
+static void initSocketFromFdNative(JNIEnv *env, jobject obj, jint fd) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+
+ struct asocket *s = asocket_init(fd);
+
+ if (!s) {
+ LOGV("asocket_init() failed, throwing");
+ jniThrowIOException(env, errno);
+ return;
+ }
+
+ env->SetIntField(obj, field_mSocketData, (jint)s);
+
+ return;
+#endif
+ jniThrowIOException(env, ENOSYS);
+}
+
+static void initSocketNative(JNIEnv *env, jobject obj) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+
+ int fd;
+ int lm = 0;
+ jboolean auth;
+ jboolean encrypt;
+ jint type;
+
+ type = env->GetIntField(obj, field_mType);
+
+ switch (type) {
+ case TYPE_RFCOMM:
+ fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ break;
+ case TYPE_SCO:
+ fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+ break;
+ case TYPE_L2CAP:
+ fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+ break;
+ default:
+ jniThrowIOException(env, ENOSYS);
+ return;
+ }
+
+ if (fd < 0) {
+ LOGV("socket() failed, throwing");
+ jniThrowIOException(env, errno);
+ return;
+ }
+
+ auth = env->GetBooleanField(obj, field_mAuth);
+ encrypt = env->GetBooleanField(obj, field_mEncrypt);
+
+ /* kernel does not yet support LM for SCO */
+ switch (type) {
+ case TYPE_RFCOMM:
+ lm |= auth ? RFCOMM_LM_AUTH : 0;
+ lm |= encrypt? RFCOMM_LM_ENCRYPT : 0;
+ break;
+ case TYPE_L2CAP:
+ lm |= auth ? L2CAP_LM_AUTH : 0;
+ lm |= encrypt? L2CAP_LM_ENCRYPT : 0;
+ break;
+ }
+
+ if (lm) {
+ if (setsockopt(fd, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm))) {
+ LOGV("setsockopt() failed, throwing");
+ jniThrowIOException(env, errno);
+ return;
+ }
+ }
+
+ LOGV("...fd %d created (%s, lm = %x)", fd, TYPE_AS_STR(type), lm);
+
+ initSocketFromFdNative(env, obj, fd);
+ return;
+#endif
+ jniThrowIOException(env, ENOSYS);
+}
+
+static void connectNative(JNIEnv *env, jobject obj) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+
+ int ret;
+ jint type;
+ const char *c_address;
+ jstring address;
+ bdaddr_t bdaddress;
+ socklen_t addr_sz;
+ struct sockaddr *addr;
+ struct asocket *s = get_socketData(env, obj);
+
+ if (!s)
+ return;
+
+ type = env->GetIntField(obj, field_mType);
+
+ /* parse address into bdaddress */
+ address = (jstring) env->GetObjectField(obj, field_mAddress);
+ c_address = env->GetStringUTFChars(address, NULL);
+ if (get_bdaddr(c_address, &bdaddress)) {
+ env->ReleaseStringUTFChars(address, c_address);
+ jniThrowIOException(env, EINVAL);
+ return;
+ }
+ env->ReleaseStringUTFChars(address, c_address);
+
+ switch (type) {
+ case TYPE_RFCOMM:
+ struct sockaddr_rc addr_rc;
+ addr = (struct sockaddr *)&addr_rc;
+ addr_sz = sizeof(addr_rc);
+
+ memset(addr, 0, addr_sz);
+ addr_rc.rc_family = AF_BLUETOOTH;
+ addr_rc.rc_channel = env->GetIntField(obj, field_mPort);
+ memcpy(&addr_rc.rc_bdaddr, &bdaddress, sizeof(bdaddr_t));
+
+ break;
+ case TYPE_SCO:
+ struct sockaddr_sco addr_sco;
+ addr = (struct sockaddr *)&addr_sco;
+ addr_sz = sizeof(addr_sco);
+
+ memset(addr, 0, addr_sz);
+ addr_sco.sco_family = AF_BLUETOOTH;
+ memcpy(&addr_sco.sco_bdaddr, &bdaddress, sizeof(bdaddr_t));
+
+ break;
+ case TYPE_L2CAP:
+ struct sockaddr_l2 addr_l2;
+ addr = (struct sockaddr *)&addr_l2;
+ addr_sz = sizeof(addr_l2);
+
+ memset(addr, 0, addr_sz);
+ addr_l2.l2_family = AF_BLUETOOTH;
+ addr_l2.l2_psm = env->GetIntField(obj, field_mPort);
+ memcpy(&addr_l2.l2_bdaddr, &bdaddress, sizeof(bdaddr_t));
+
+ break;
+ default:
+ jniThrowIOException(env, ENOSYS);
+ return;
+ }
+
+ ret = asocket_connect(s, addr, addr_sz, -1);
+ LOGV("...connect(%d, %s) = %d (errno %d)",
+ s->fd, TYPE_AS_STR(type), ret, errno);
+
+ if (ret)
+ jniThrowIOException(env, errno);
+
+ return;
+#endif
+ jniThrowIOException(env, ENOSYS);
+}
+
+static void bindListenNative(JNIEnv *env, jobject obj) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+
+ jint type;
+ socklen_t addr_sz;
+ struct sockaddr *addr;
+ bdaddr_t bdaddr = *BDADDR_ANY;
+ struct asocket *s = get_socketData(env, obj);
+
+ if (!s)
+ return;
+
+ type = env->GetIntField(obj, field_mType);
+
+ switch (type) {
+ case TYPE_RFCOMM:
+ struct sockaddr_rc addr_rc;
+ addr = (struct sockaddr *)&addr_rc;
+ addr_sz = sizeof(addr_rc);
+
+ memset(addr, 0, addr_sz);
+ addr_rc.rc_family = AF_BLUETOOTH;
+ addr_rc.rc_channel = env->GetIntField(obj, field_mPort);
+ memcpy(&addr_rc.rc_bdaddr, &bdaddr, sizeof(bdaddr_t));
+ break;
+ case TYPE_SCO:
+ struct sockaddr_sco addr_sco;
+ addr = (struct sockaddr *)&addr_sco;
+ addr_sz = sizeof(addr_sco);
+
+ memset(addr, 0, addr_sz);
+ addr_sco.sco_family = AF_BLUETOOTH;
+ memcpy(&addr_sco.sco_bdaddr, &bdaddr, sizeof(bdaddr_t));
+ break;
+ case TYPE_L2CAP:
+ struct sockaddr_l2 addr_l2;
+ addr = (struct sockaddr *)&addr_l2;
+ addr_sz = sizeof(addr_l2);
+
+ memset(addr, 0, addr_sz);
+ addr_l2.l2_family = AF_BLUETOOTH;
+ addr_l2.l2_psm = env->GetIntField(obj, field_mPort);
+ memcpy(&addr_l2.l2_bdaddr, &bdaddr, sizeof(bdaddr_t));
+ break;
+ default:
+ jniThrowIOException(env, ENOSYS);
+ return;
+ }
+
+ if (bind(s->fd, addr, addr_sz)) {
+ jniThrowIOException(env, errno);
+ return;
+ }
+
+ if (listen(s->fd, 1)) {
+ jniThrowIOException(env, errno);
+ return;
+ }
+
+ return;
+#endif
+ jniThrowIOException(env, ENOSYS);
+}
+
+static jobject acceptNative(JNIEnv *env, jobject obj, int timeout) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+
+ int fd;
+ jint type;
+ struct sockaddr *addr;
+ socklen_t addr_sz;
+ jstring addr_jstr;
+ char addr_cstr[BTADDR_SIZE];
+ bdaddr_t *bdaddr;
+ jboolean auth;
+ jboolean encrypt;
+
+ struct asocket *s = get_socketData(env, obj);
+
+ if (!s)
+ return NULL;
+
+ type = env->GetIntField(obj, field_mType);
+
+ switch (type) {
+ case TYPE_RFCOMM:
+ struct sockaddr_rc addr_rc;
+ addr = (struct sockaddr *)&addr_rc;
+ addr_sz = sizeof(addr_rc);
+ bdaddr = &addr_rc.rc_bdaddr;
+ memset(addr, 0, addr_sz);
+ break;
+ case TYPE_SCO:
+ struct sockaddr_sco addr_sco;
+ addr = (struct sockaddr *)&addr_sco;
+ addr_sz = sizeof(addr_sco);
+ bdaddr = &addr_sco.sco_bdaddr;
+ memset(addr, 0, addr_sz);
+ break;
+ case TYPE_L2CAP:
+ struct sockaddr_l2 addr_l2;
+ addr = (struct sockaddr *)&addr_l2;
+ addr_sz = sizeof(addr_l2);
+ bdaddr = &addr_l2.l2_bdaddr;
+ memset(addr, 0, addr_sz);
+ break;
+ default:
+ jniThrowIOException(env, ENOSYS);
+ return NULL;
+ }
+
+ fd = asocket_accept(s, addr, &addr_sz, timeout);
+
+ LOGV("...accept(%d, %s) = %d (errno %d)",
+ s->fd, TYPE_AS_STR(type), fd, errno);
+
+ if (fd < 0) {
+ jniThrowIOException(env, errno);
+ return NULL;
+ }
+
+ /* Connected - return new BluetoothSocket */
+ auth = env->GetBooleanField(obj, field_mAuth);
+ encrypt = env->GetBooleanField(obj, field_mEncrypt);
+
+ get_bdaddr_as_string(bdaddr, addr_cstr);
+
+ addr_jstr = env->NewStringUTF(addr_cstr);
+ return env->NewObject(class_BluetoothSocket, method_BluetoothSocket_ctor,
+ type, fd, auth, encrypt, addr_jstr, -1);
+
+#endif
+ jniThrowIOException(env, ENOSYS);
+ return NULL;
+}
+
+static jint availableNative(JNIEnv *env, jobject obj) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+
+ int available;
+ struct asocket *s = get_socketData(env, obj);
+
+ if (!s)
+ return -1;
+
+ if (ioctl(s->fd, FIONREAD, &available) < 0) {
+ jniThrowIOException(env, errno);
+ return -1;
+ }
+
+ return available;
+
+#endif
+ jniThrowIOException(env, ENOSYS);
+ return -1;
+}
+
+/** jb must not be null. offset and offset+length must be within array */
+static jint readNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset,
+ jint length) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+
+ int ret;
+ jbyte *b;
+ struct asocket *s = get_socketData(env, obj);
+
+ if (!s)
+ return -1;
+
+ b = env->GetByteArrayElements(jb, NULL);
+ if (b == NULL) {
+ jniThrowIOException(env, EINVAL);
+ return -1;
+ }
+
+ ret = asocket_read(s, &b[offset], length, -1);
+ if (ret < 0) {
+ jniThrowIOException(env, errno);
+ env->ReleaseByteArrayElements(jb, b, JNI_ABORT);
+ return -1;
+ }
+
+ env->ReleaseByteArrayElements(jb, b, 0);
+ return (jint)ret;
+
+#endif
+ jniThrowIOException(env, ENOSYS);
+ return -1;
+}
+
+/** jb must not be null. offset and offset+length must be within array */
+static jint writeNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset,
+ jint length) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+
+ int ret;
+ jbyte *b;
+ struct asocket *s = get_socketData(env, obj);
+
+ if (!s)
+ return -1;
+
+ b = env->GetByteArrayElements(jb, NULL);
+ if (b == NULL) {
+ jniThrowIOException(env, EINVAL);
+ return -1;
+ }
+
+ ret = asocket_write(s, &b[offset], length, -1);
+ if (ret < 0) {
+ jniThrowIOException(env, errno);
+ env->ReleaseByteArrayElements(jb, b, JNI_ABORT);
+ return -1;
+ }
+
+ env->ReleaseByteArrayElements(jb, b, JNI_ABORT); // no need to commit
+ return (jint)ret;
+
+#endif
+ jniThrowIOException(env, ENOSYS);
+ return -1;
+}
+
+static void closeNative(JNIEnv *env, jobject obj) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ struct asocket *s = get_socketData(env, obj);
+
+ if (!s)
+ return;
+
+ asocket_abort(s);
+
+ LOGV("...asocket_abort(%d) complete", s->fd);
+ return;
+#endif
+ jniThrowIOException(env, ENOSYS);
+}
+
+static void destroyNative(JNIEnv *env, jobject obj) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ struct asocket *s = get_socketData(env, obj);
+ int fd = s->fd;
+
+ if (!s)
+ return;
+
+ asocket_destroy(s);
+
+ LOGV("...asocket_destroy(%d) complete", fd);
+ return;
+#endif
+ jniThrowIOException(env, ENOSYS);
+}
+
+static JNINativeMethod sMethods[] = {
+ {"initSocketNative", "()V", (void*) initSocketNative},
+ {"initSocketFromFdNative", "(I)V", (void*) initSocketFromFdNative},
+ {"connectNative", "()V", (void *) connectNative},
+ {"bindListenNative", "()V", (void *) bindListenNative},
+ {"acceptNative", "(I)Landroid/bluetooth/BluetoothSocket;", (void *) acceptNative},
+ {"availableNative", "()I", (void *) availableNative},
+ {"readNative", "([BII)I", (void *) readNative},
+ {"writeNative", "([BII)I", (void *) writeNative},
+ {"closeNative", "()V", (void *) closeNative},
+ {"destroyNative", "()V", (void *) destroyNative},
+};
+
+int register_android_bluetooth_BluetoothSocket(JNIEnv *env) {
+ jclass clazz = env->FindClass("android/bluetooth/BluetoothSocket");
+ if (clazz == NULL)
+ return -1;
+ class_BluetoothSocket = (jclass) env->NewGlobalRef(clazz);
+ field_mType = env->GetFieldID(clazz, "mType", "I");
+ field_mAddress = env->GetFieldID(clazz, "mAddress", "Ljava/lang/String;");
+ field_mPort = env->GetFieldID(clazz, "mPort", "I");
+ field_mAuth = env->GetFieldID(clazz, "mAuth", "Z");
+ field_mEncrypt = env->GetFieldID(clazz, "mEncrypt", "Z");
+ field_mSocketData = env->GetFieldID(clazz, "mSocketData", "I");
+ method_BluetoothSocket_ctor = env->GetMethodID(clazz, "<init>", "(IIZZLjava/lang/String;I)V");
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/bluetooth/BluetoothSocket", sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
+
diff --git a/core/jni/android_bluetooth_Database.cpp b/core/jni/android_bluetooth_Database.cpp
deleted file mode 100644
index 136c9a3..0000000
--- a/core/jni/android_bluetooth_Database.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * 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.
- */
-
-#define DBUS_CLASS_NAME BLUEZ_DBUS_BASE_IFC ".Database"
-#define LOG_TAG "bluetooth_Database.cpp"
-
-#include "android_bluetooth_common.h"
-#include "android_runtime/AndroidRuntime.h"
-#include "JNIHelp.h"
-#include "jni.h"
-#include "utils/Log.h"
-
-#ifdef HAVE_BLUETOOTH
-#include <dbus/dbus.h>
-#endif
-
-namespace android {
-
-#ifdef HAVE_BLUETOOTH
-static DBusConnection* conn = NULL; // Singleton thread-safe connection
-#endif
-
-static void classInitNative(JNIEnv* env, jclass clazz) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- conn = NULL;
-#endif
-}
-
-static void initializeNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
-
-#ifdef HAVE_BLUETOOTH
- if (conn == NULL) {
- DBusError err;
- dbus_error_init(&err);
- dbus_threads_init_default();
- conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
- if (dbus_error_is_set(&err)) {
- LOGE("Could not get onto the system bus!");
- dbus_error_free(&err);
- }
- }
-#endif
-}
-
-static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
-}
-
-static jint addServiceRecordNative(JNIEnv *env, jobject object,
- jbyteArray record) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- if (conn != NULL) {
- jbyte* c_record = env->GetByteArrayElements(record, NULL);
- DBusMessage *reply = dbus_func_args(env,
- conn,
- BLUEZ_DBUS_BASE_PATH,
- DBUS_CLASS_NAME,
- "AddServiceRecord",
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
- &c_record,
- env->GetArrayLength(record),
- DBUS_TYPE_INVALID);
- env->ReleaseByteArrayElements(record, c_record, JNI_ABORT);
- return reply ? dbus_returns_uint32(env, reply) : -1;
- }
-#endif
- return -1;
-}
-
-static jint addServiceRecordFromXmlNative(JNIEnv *env, jobject object,
- jstring record) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- if (conn != NULL) {
- const char *c_record = env->GetStringUTFChars(record, NULL);
- DBusMessage *reply = dbus_func_args(env,
- conn,
- BLUEZ_DBUS_BASE_PATH,
- DBUS_CLASS_NAME,
- "AddServiceRecordFromXML",
- DBUS_TYPE_STRING, &c_record,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(record, c_record);
- return reply ? dbus_returns_uint32(env, reply) : -1;
- }
-#endif
- return -1;
-}
-
-static void updateServiceRecordNative(JNIEnv *env, jobject object,
- jint handle,
- jbyteArray record) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- if (conn != NULL) {
- jbyte* c_record = env->GetByteArrayElements(record, NULL);
- DBusMessage *reply = dbus_func_args(env,
- conn,
- BLUEZ_DBUS_BASE_PATH,
- DBUS_CLASS_NAME,
- "UpdateServiceRecord",
- DBUS_TYPE_UINT32, &handle,
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
- &c_record,
- env->GetArrayLength(record),
- DBUS_TYPE_INVALID);
- env->ReleaseByteArrayElements(record, c_record, JNI_ABORT);
- }
-#endif
-}
-
-static void updateServiceRecordFromXmlNative(JNIEnv *env, jobject object,
- jint handle,
- jstring record) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- if (conn != NULL) {
- const char *c_record = env->GetStringUTFChars(record, NULL);
- DBusMessage *reply = dbus_func_args(env,
- conn,
- BLUEZ_DBUS_BASE_PATH,
- DBUS_CLASS_NAME,
- "UpdateServiceRecordFromXML",
- DBUS_TYPE_UINT32, &handle,
- DBUS_TYPE_STRING, &c_record,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(record, c_record);
- }
-#endif
-}
-
-/* private static native void removeServiceRecordNative(int handle); */
-static void removeServiceRecordNative(JNIEnv *env, jobject object,
- jint handle) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- if (conn != NULL) {
- DBusMessage *reply = dbus_func_args(env,
- conn,
- BLUEZ_DBUS_BASE_PATH,
- DBUS_CLASS_NAME,
- "RemoveServiceRecord",
- DBUS_TYPE_UINT32, &handle,
- DBUS_TYPE_INVALID);
- }
-#endif
-}
-
-
-static JNINativeMethod sMethods[] = {
- /* name, signature, funcPtr */
- {"classInitNative", "()V", (void*)classInitNative},
- {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
- {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
- {"addServiceRecordNative", "([B)I", (void*)addServiceRecordNative},
- {"addServiceRecordFromXmlNative", "(Ljava/lang/String;)I", (void*)addServiceRecordFromXmlNative},
- {"updateServiceRecordNative", "(I[B)V", (void*)updateServiceRecordNative},
- {"updateServiceRecordFromXmlNative", "(ILjava/lang/String;)V", (void*)updateServiceRecordFromXmlNative},
- {"removeServiceRecordNative", "(I)V", (void*)removeServiceRecordNative},
-};
-
-int register_android_bluetooth_Database(JNIEnv *env) {
- return AndroidRuntime::registerNativeMethods(env,
- "android/bluetooth/Database", sMethods, NELEM(sMethods));
-}
-
-} /* namespace android */
diff --git a/core/jni/android_bluetooth_RfcommSocket.cpp b/core/jni/android_bluetooth_RfcommSocket.cpp
deleted file mode 100644
index 3ed35d9..0000000
--- a/core/jni/android_bluetooth_RfcommSocket.cpp
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
-** 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.
-*/
-
-#define LOG_TAG "bluetooth_RfcommSocket.cpp"
-
-#include "android_bluetooth_common.h"
-#include "android_runtime/AndroidRuntime.h"
-#include "JNIHelp.h"
-#include "jni.h"
-#include "utils/Log.h"
-#include "utils/misc.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <sys/poll.h>
-
-#ifdef HAVE_BLUETOOTH
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/sco.h>
-#endif
-
-namespace android {
-
-#ifdef HAVE_BLUETOOTH
-static jfieldID field_mNativeData;
-static jfieldID field_mTimeoutRemainingMs;
-static jfieldID field_mAcceptTimeoutRemainingMs;
-static jfieldID field_mAddress;
-static jfieldID field_mPort;
-
-typedef struct {
- jstring address;
- const char *c_address;
- int rfcomm_channel;
- int last_read_err;
- int rfcomm_sock;
- // < 0 -- in progress,
- // 0 -- not connected
- // > 0 connected
- // 1 input is open
- // 2 output is open
- // 3 both input and output are open
- int rfcomm_connected;
- int rfcomm_sock_flags;
-} native_data_t;
-
-static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
- return (native_data_t *)(env->GetIntField(object, field_mNativeData));
-}
-
-static inline void init_socket_info(
- JNIEnv *env, jobject object,
- native_data_t *nat,
- jstring address,
- jint rfcomm_channel) {
- nat->address = (jstring)env->NewGlobalRef(address);
- nat->c_address = env->GetStringUTFChars(nat->address, NULL);
- nat->rfcomm_channel = (int)rfcomm_channel;
-}
-
-static inline void cleanup_socket_info(JNIEnv *env, native_data_t *nat) {
- if (nat->c_address != NULL) {
- env->ReleaseStringUTFChars(nat->address, nat->c_address);
- env->DeleteGlobalRef(nat->address);
- nat->c_address = NULL;
- }
-}
-#endif
-
-static void classInitNative(JNIEnv* env, jclass clazz) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- field_mNativeData = get_field(env, clazz, "mNativeData", "I");
- field_mTimeoutRemainingMs = get_field(env, clazz, "mTimeoutRemainingMs", "I");
- field_mAcceptTimeoutRemainingMs = get_field(env, clazz, "mAcceptTimeoutRemainingMs", "I");
- field_mAddress = get_field(env, clazz, "mAddress", "Ljava/lang/String;");
- field_mPort = get_field(env, clazz, "mPort", "I");
-#endif
-}
-
-static void initializeNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
-
- native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
- if (nat == NULL) {
- LOGE("%s: out of memory!", __FUNCTION__);
- return;
- }
-
- env->SetIntField(object, field_mNativeData, (jint)nat);
- nat->rfcomm_sock = -1;
- nat->rfcomm_connected = 0;
-#endif
-}
-
-static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- free(nat);
- }
-#endif
-}
-
-static jobject createNative(JNIEnv *env, jobject obj) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- int lm;
- native_data_t *nat = get_native_data(env, obj);
- nat->rfcomm_sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
-
- if (nat->rfcomm_sock < 0) {
- LOGE("%s: Could not create RFCOMM socket: %s\n", __FUNCTION__,
- strerror(errno));
- return NULL;
- }
-
- lm = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
-
- if (lm && setsockopt(nat->rfcomm_sock, SOL_RFCOMM, RFCOMM_LM, &lm,
- sizeof(lm)) < 0) {
- LOGE("%s: Can't set RFCOMM link mode", __FUNCTION__);
- close(nat->rfcomm_sock);
- return NULL;
- }
-
- return jniCreateFileDescriptor(env, nat->rfcomm_sock);
-#else
- return NULL;
-#endif
-}
-
-static void destroyNative(JNIEnv *env, jobject obj) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, obj);
- cleanup_socket_info(env, nat);
- if (nat->rfcomm_sock >= 0) {
- close(nat->rfcomm_sock);
- nat->rfcomm_sock = -1;
- }
-#endif
-}
-
-
-static jboolean connectNative(JNIEnv *env, jobject obj,
- jstring address, jint port) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, obj);
-
- if (nat->rfcomm_sock >= 0) {
- if (nat->rfcomm_connected) {
- LOGI("RFCOMM socket: %s.",
- (nat->rfcomm_connected > 0) ? "already connected" : "connection is in progress");
- return JNI_TRUE;
- }
-
- init_socket_info(env, obj, nat, address, port);
-
- struct sockaddr_rc addr;
- memset(&addr, 0, sizeof(struct sockaddr_rc));
- get_bdaddr(nat->c_address, &addr.rc_bdaddr);
- addr.rc_channel = nat->rfcomm_channel;
- addr.rc_family = AF_BLUETOOTH;
- nat->rfcomm_connected = 0;
-
- while (nat->rfcomm_connected == 0) {
- if (connect(nat->rfcomm_sock, (struct sockaddr *)&addr,
- sizeof(addr)) < 0) {
- if (errno == EINTR) continue;
- LOGE("connect error: %s (%d)\n", strerror(errno), errno);
- break;
- } else {
- nat->rfcomm_connected = 3; // input and output
- }
- }
- } else {
- LOGE("%s: socket(RFCOMM) error: socket not created", __FUNCTION__);
- }
-
- if (nat->rfcomm_connected > 0) {
- env->SetIntField(obj, field_mPort, port);
- return JNI_TRUE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static jboolean connectAsyncNative(JNIEnv *env, jobject obj,
- jstring address, jint port) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, obj);
-
- if (nat->rfcomm_sock < 0) {
- LOGE("%s: socket(RFCOMM) error: socket not created", __FUNCTION__);
- return JNI_FALSE;
- }
-
- if (nat->rfcomm_connected) {
- LOGI("RFCOMM socket: %s.",
- (nat->rfcomm_connected > 0) ?
- "already connected" : "connection is in progress");
- return JNI_TRUE;
- }
-
- init_socket_info(env, obj, nat, address, port);
-
- struct sockaddr_rc addr;
- memset(&addr, 0, sizeof(struct sockaddr_rc));
- get_bdaddr(nat->c_address, &addr.rc_bdaddr);
- addr.rc_channel = nat->rfcomm_channel;
- addr.rc_family = AF_BLUETOOTH;
-
- nat->rfcomm_sock_flags = fcntl(nat->rfcomm_sock, F_GETFL, 0);
- if (fcntl(nat->rfcomm_sock,
- F_SETFL, nat->rfcomm_sock_flags | O_NONBLOCK) >= 0) {
- int rc;
- nat->rfcomm_connected = 0;
- errno = 0;
- rc = connect(nat->rfcomm_sock,
- (struct sockaddr *)&addr,
- sizeof(addr));
-
- if (rc >= 0) {
- nat->rfcomm_connected = 3;
- LOGI("RFCOMM async connect immediately successful");
- env->SetIntField(obj, field_mPort, port);
- return JNI_TRUE;
- }
- else if (rc < 0) {
- if (errno == EINPROGRESS || errno == EAGAIN)
- {
- LOGI("RFCOMM async connect is in progress (%s)",
- strerror(errno));
- nat->rfcomm_connected = -1;
- env->SetIntField(obj, field_mPort, port);
- return JNI_TRUE;
- }
- else
- {
- LOGE("RFCOMM async connect error (%d): %s (%d)",
- nat->rfcomm_sock, strerror(errno), errno);
- return JNI_FALSE;
- }
- }
- } // fcntl(nat->rfcomm_sock ...)
-#endif
- return JNI_FALSE;
-}
-
-static jboolean interruptAsyncConnectNative(JNIEnv *env, jobject obj) {
- //WRITEME
- return JNI_TRUE;
-}
-
-static jint waitForAsyncConnectNative(JNIEnv *env, jobject obj,
- jint timeout_ms) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- struct sockaddr_rc addr;
- native_data_t *nat = get_native_data(env, obj);
-
- env->SetIntField(obj, field_mTimeoutRemainingMs, timeout_ms);
-
- if (nat->rfcomm_sock < 0) {
- LOGE("%s: socket(RFCOMM) error: socket not created", __FUNCTION__);
- return -1;
- }
-
- if (nat->rfcomm_connected > 0) {
- LOGI("%s: RFCOMM is already connected!", __FUNCTION__);
- return 1;
- }
-
- /* Do an asynchronous select() */
- int n;
- fd_set rset, wset;
- struct timeval to;
-
- FD_ZERO(&rset);
- FD_ZERO(&wset);
- FD_SET(nat->rfcomm_sock, &rset);
- FD_SET(nat->rfcomm_sock, &wset);
- if (timeout_ms >= 0) {
- to.tv_sec = timeout_ms / 1000;
- to.tv_usec = 1000 * (timeout_ms % 1000);
- }
- n = select(nat->rfcomm_sock + 1,
- &rset,
- &wset,
- NULL,
- (timeout_ms < 0 ? NULL : &to));
-
- if (timeout_ms > 0) {
- jint remaining = to.tv_sec*1000 + to.tv_usec/1000;
- LOGI("Remaining time %ldms", (long)remaining);
- env->SetIntField(obj, field_mTimeoutRemainingMs,
- remaining);
- }
-
- if (n <= 0) {
- if (n < 0) {
- LOGE("select() on RFCOMM socket: %s (%d)",
- strerror(errno),
- errno);
- return -1;
- }
- return 0;
- }
- /* n must be equal to 1 and either rset or wset must have the
- file descriptor set. */
- LOGI("select() returned %d.", n);
- if (FD_ISSET(nat->rfcomm_sock, &rset) ||
- FD_ISSET(nat->rfcomm_sock, &wset)) {
- /* A trial async read() will tell us if everything is OK. */
- char ch;
- errno = 0;
- int nr = read(nat->rfcomm_sock, &ch, 1);
- /* It should be that nr != 1 because we just opened a socket
- and we haven't sent anything over it for the other side to
- respond... but one can't be paranoid enough.
- */
- if (nr >= 0 || errno != EAGAIN) {
- LOGE("RFCOMM async connect() error: %s (%d), nr = %d\n",
- strerror(errno),
- errno,
- nr);
- /* Clear the rfcomm_connected flag to cause this function
- to re-create the socket and re-attempt the connect()
- the next time it is called.
- */
- nat->rfcomm_connected = 0;
- /* Restore the blocking properties of the socket. */
- fcntl(nat->rfcomm_sock, F_SETFL, nat->rfcomm_sock_flags);
- return -1;
- }
- /* Restore the blocking properties of the socket. */
- fcntl(nat->rfcomm_sock, F_SETFL, nat->rfcomm_sock_flags);
- LOGI("Successful RFCOMM socket connect.");
- nat->rfcomm_connected = 3; // input and output
- return 1;
- }
-#endif
- return -1;
-}
-
-static jboolean shutdownNative(JNIEnv *env, jobject obj,
- jboolean shutdownInput) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- /* NOTE: If you change the bcode to modify nat, make sure you
- add synchronize(this) to the method calling this native
- method.
- */
- native_data_t *nat = get_native_data(env, obj);
- if (nat->rfcomm_sock < 0) {
- LOGE("socket(RFCOMM) error: socket not created");
- return JNI_FALSE;
- }
- int rc = shutdown(nat->rfcomm_sock,
- shutdownInput ? SHUT_RD : SHUT_WR);
- if (!rc) {
- nat->rfcomm_connected &=
- shutdownInput ? ~1 : ~2;
- return JNI_TRUE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static jint isConnectedNative(JNIEnv *env, jobject obj) {
- LOGI(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- const native_data_t *nat = get_native_data(env, obj);
- return nat->rfcomm_connected;
-#endif
- return 0;
-}
-
-//@@@@@@@@@ bind to device???
-static jboolean bindNative(JNIEnv *env, jobject obj, jstring device,
- jint port) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
-
- /* NOTE: If you change the code to modify nat, make sure you
- add synchronize(this) to the method calling this native
- method.
- */
- const native_data_t *nat = get_native_data(env, obj);
- if (nat->rfcomm_sock < 0) {
- LOGE("socket(RFCOMM) error: socket not created");
- return JNI_FALSE;
- }
-
- struct sockaddr_rc laddr;
- int lm;
-
- lm = 0;
-/*
- lm |= RFCOMM_LM_MASTER;
- lm |= RFCOMM_LM_AUTH;
- lm |= RFCOMM_LM_ENCRYPT;
- lm |= RFCOMM_LM_SECURE;
-*/
-
- if (lm && setsockopt(nat->rfcomm_sock, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) {
- LOGE("Can't set RFCOMM link mode");
- return JNI_FALSE;
- }
-
- laddr.rc_family = AF_BLUETOOTH;
- bacpy(&laddr.rc_bdaddr, BDADDR_ANY);
- laddr.rc_channel = port;
-
- if (bind(nat->rfcomm_sock, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {
- LOGE("Can't bind RFCOMM socket");
- return JNI_FALSE;
- }
-
- env->SetIntField(obj, field_mPort, port);
-
- return JNI_TRUE;
-#endif
- return JNI_FALSE;
-}
-
-static jboolean listenNative(JNIEnv *env, jobject obj, jint backlog) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- /* NOTE: If you change the code to modify nat, make sure you
- add synchronize(this) to the method calling this native
- method.
- */
- const native_data_t *nat = get_native_data(env, obj);
- if (nat->rfcomm_sock < 0) {
- LOGE("socket(RFCOMM) error: socket not created");
- return JNI_FALSE;
- }
- return listen(nat->rfcomm_sock, backlog) < 0 ? JNI_FALSE : JNI_TRUE;
-#else
- return JNI_FALSE;
-#endif
-}
-
-static int set_nb(int sk, bool nb) {
- int flags = fcntl(sk, F_GETFL);
- if (flags < 0) {
- LOGE("Can't get socket flags with fcntl(): %s (%d)",
- strerror(errno), errno);
- close(sk);
- return -1;
- }
- flags &= ~O_NONBLOCK;
- if (nb) flags |= O_NONBLOCK;
- int status = fcntl(sk, F_SETFL, flags);
- if (status < 0) {
- LOGE("Can't set socket to nonblocking mode with fcntl(): %s (%d)",
- strerror(errno), errno);
- close(sk);
- return -1;
- }
- return 0;
-}
-
-// Note: the code should check at a higher level to see whether
-// listen() has been called.
-#ifdef HAVE_BLUETOOTH
-static int do_accept(JNIEnv* env, jobject object, int sock,
- jobject newsock,
- jfieldID out_address,
- bool must_succeed) {
-
- if (must_succeed && set_nb(sock, true) < 0)
- return -1;
-
- struct sockaddr_rc raddr;
- int alen = sizeof(raddr);
- int nsk = accept(sock, (struct sockaddr *) &raddr, &alen);
- if (nsk < 0) {
- LOGE("Error on accept from socket fd %d: %s (%d).",
- sock,
- strerror(errno),
- errno);
- if (must_succeed) set_nb(sock, false);
- return -1;
- }
-
- char addr[BTADDR_SIZE];
- get_bdaddr_as_string(&raddr.rc_bdaddr, addr);
- env->SetObjectField(newsock, out_address, env->NewStringUTF(addr));
-
- LOGI("Successful accept() on AG socket %d: new socket %d, address %s, RFCOMM channel %d",
- sock,
- nsk,
- addr,
- raddr.rc_channel);
- if (must_succeed) set_nb(sock, false);
- return nsk;
-}
-#endif /*HAVE_BLUETOOTH*/
-
-static jobject acceptNative(JNIEnv *env, jobject obj,
- jobject newsock, jint timeoutMs) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, obj);
- if (nat->rfcomm_sock < 0) {
- LOGE("socket(RFCOMM) error: socket not created");
- return JNI_FALSE;
- }
-
- if (newsock == NULL) {
- LOGE("%s: newsock = NULL\n", __FUNCTION__);
- return JNI_FALSE;
- }
-
- int nsk = -1;
- if (timeoutMs < 0) {
- /* block until accept() succeeds */
- nsk = do_accept(env, obj, nat->rfcomm_sock,
- newsock, field_mAddress, false);
- if (nsk < 0) {
- return NULL;
- }
- }
- else {
- /* wait with a timeout */
-
- struct pollfd fds;
- fds.fd = nat->rfcomm_sock;
- fds.events = POLLIN | POLLPRI | POLLOUT | POLLERR;
-
- env->SetIntField(obj, field_mAcceptTimeoutRemainingMs, 0);
- int n = poll(&fds, 1, timeoutMs);
- if (n <= 0) {
- if (n < 0) {
- LOGE("listening poll() on RFCOMM socket: %s (%d)",
- strerror(errno),
- errno);
- env->SetIntField(obj, field_mAcceptTimeoutRemainingMs, timeoutMs);
- }
- else {
- LOGI("listening poll() on RFCOMM socket timed out");
- }
- return NULL;
- }
-
- LOGI("listening poll() on RFCOMM socket returned %d", n);
- if (fds.fd == nat->rfcomm_sock) {
- if (fds.revents & (POLLIN | POLLPRI | POLLOUT)) {
- LOGI("Accepting connection.\n");
- nsk = do_accept(env, obj, nat->rfcomm_sock,
- newsock, field_mAddress, true);
- if (nsk < 0) {
- return NULL;
- }
- }
- }
- }
-
- LOGI("Connection accepted, new socket fd = %d.", nsk);
- native_data_t *newnat = get_native_data(env, newsock);
- newnat->rfcomm_sock = nsk;
- newnat->rfcomm_connected = 3;
- return jniCreateFileDescriptor(env, nsk);
-#else
- return NULL;
-#endif
-}
-
-static JNINativeMethod sMethods[] = {
- /* name, signature, funcPtr */
- {"classInitNative", "()V", (void*)classInitNative},
- {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
- {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
-
- {"createNative", "()Ljava/io/FileDescriptor;", (void *)createNative},
- {"destroyNative", "()V", (void *)destroyNative},
- {"connectNative", "(Ljava/lang/String;I)Z", (void *)connectNative},
- {"connectAsyncNative", "(Ljava/lang/String;I)Z", (void *)connectAsyncNative},
- {"interruptAsyncConnectNative", "()Z", (void *)interruptAsyncConnectNative},
- {"waitForAsyncConnectNative", "(I)I", (void *)waitForAsyncConnectNative},
- {"shutdownNative", "(Z)Z", (void *)shutdownNative},
- {"isConnectedNative", "()I", (void *)isConnectedNative},
-
- {"bindNative", "(Ljava/lang/String;I)Z", (void*)bindNative},
- {"listenNative", "(I)Z", (void*)listenNative},
- {"acceptNative", "(Landroid/bluetooth/RfcommSocket;I)Ljava/io/FileDescriptor;", (void*)acceptNative},
-};
-
-int register_android_bluetooth_RfcommSocket(JNIEnv *env) {
- return AndroidRuntime::registerNativeMethods(env,
- "android/bluetooth/RfcommSocket", sMethods, NELEM(sMethods));
-}
-
-} /* namespace android */
diff --git a/core/jni/android_bluetooth_common.cpp b/core/jni/android_bluetooth_common.cpp
index 0b8a604..ee672f7 100644
--- a/core/jni/android_bluetooth_common.cpp
+++ b/core/jni/android_bluetooth_common.cpp
@@ -390,17 +390,18 @@ jbyteArray dbus_returns_array_of_bytes(JNIEnv *env, DBusMessage *reply) {
return byteArray;
}
-void get_bdaddr(const char *str, bdaddr_t *ba) {
+int get_bdaddr(const char *str, bdaddr_t *ba) {
char *d = ((char *)ba) + 5, *endp;
int i;
for(i = 0; i < 6; i++) {
*d-- = strtol(str, &endp, 16);
if (*endp != ':' && i != 5) {
memset(ba, 0, sizeof(bdaddr_t));
- return;
+ return -1;
}
str = endp + 1;
}
+ return 0;
}
void get_bdaddr_as_string(const bdaddr_t *ba, char *str) {
diff --git a/core/jni/android_bluetooth_common.h b/core/jni/android_bluetooth_common.h
index 69092dd..e5b8813 100644
--- a/core/jni/android_bluetooth_common.h
+++ b/core/jni/android_bluetooth_common.h
@@ -144,7 +144,7 @@ jboolean dbus_returns_boolean(JNIEnv *env, DBusMessage *reply);
jobjectArray dbus_returns_array_of_strings(JNIEnv *env, DBusMessage *reply);
jbyteArray dbus_returns_array_of_bytes(JNIEnv *env, DBusMessage *reply);
-void get_bdaddr(const char *str, bdaddr_t *ba);
+int get_bdaddr(const char *str, bdaddr_t *ba);
void get_bdaddr_as_string(const bdaddr_t *ba, char *str);
bool debug_no_encrypt();
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index f19fbbf..91449bc 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -229,7 +229,7 @@ static jboolean isBlob_native(JNIEnv* env, jobject object, jint row, jint column
{
int32_t err;
CursorWindow * window = GET_WINDOW(env, object);
-LOG_WINDOW("Checking if column is a blob for %d,%d from %p", row, column, window);
+LOG_WINDOW("Checking if column is a blob or null for %d,%d from %p", row, column, window);
field_slot_t field;
err = window->read_field_slot(row, column, &field);
@@ -241,6 +241,54 @@ LOG_WINDOW("Checking if column is a blob for %d,%d from %p", row, column, window
return field.type == FIELD_TYPE_BLOB || field.type == FIELD_TYPE_NULL;
}
+static jboolean isString_native(JNIEnv* env, jobject object, jint row, jint column)
+{
+ int32_t err;
+ CursorWindow * window = GET_WINDOW(env, object);
+LOG_WINDOW("Checking if column is a string or null for %d,%d from %p", row, column, window);
+
+ field_slot_t field;
+ err = window->read_field_slot(row, column, &field);
+ if (err != 0) {
+ throwExceptionWithRowCol(env, row, column);
+ return NULL;
+ }
+
+ return field.type == FIELD_TYPE_STRING || field.type == FIELD_TYPE_NULL;
+}
+
+static jboolean isInteger_native(JNIEnv* env, jobject object, jint row, jint column)
+{
+ int32_t err;
+ CursorWindow * window = GET_WINDOW(env, object);
+LOG_WINDOW("Checking if column is an integer for %d,%d from %p", row, column, window);
+
+ field_slot_t field;
+ err = window->read_field_slot(row, column, &field);
+ if (err != 0) {
+ throwExceptionWithRowCol(env, row, column);
+ return NULL;
+ }
+
+ return field.type == FIELD_TYPE_INTEGER;
+}
+
+static jboolean isFloat_native(JNIEnv* env, jobject object, jint row, jint column)
+{
+ int32_t err;
+ CursorWindow * window = GET_WINDOW(env, object);
+LOG_WINDOW("Checking if column is a float for %d,%d from %p", row, column, window);
+
+ field_slot_t field;
+ err = window->read_field_slot(row, column, &field);
+ if (err != 0) {
+ throwExceptionWithRowCol(env, row, column);
+ return NULL;
+ }
+
+ return field.type == FIELD_TYPE_FLOAT;
+}
+
static jstring getString_native(JNIEnv* env, jobject object, jint row, jint column)
{
int32_t err;
@@ -326,11 +374,11 @@ LOG_WINDOW("Copying string for %d,%d from %p", row, column, window);
jniThrowException(env, "java/lang/IllegalStateException", "Unable to get field slot");
return NULL;
}
-
+
jcharArray buffer = (jcharArray)env->GetObjectField(buf, gBufferField);
if (buffer == NULL) {
jniThrowException(env, "java/lang/IllegalStateException", "buf should not be null");
- return NULL;
+ return NULL;
}
jchar* dst = env->GetCharArrayElements(buffer, NULL);
uint8_t type = field.type;
@@ -338,7 +386,7 @@ LOG_WINDOW("Copying string for %d,%d from %p", row, column, window);
jcharArray newArray = NULL;
if (type == FIELD_TYPE_STRING) {
uint32_t size = field.data.buffer.size;
- if (size > 0) {
+ if (size > 0) {
#if WINDOW_STORAGE_UTF8
// Pass size - 1 since the UTF8 is null terminated and we don't want a null terminator on the UTF16 string
String16 utf16((char const *)window->offsetToPtr(field.data.buffer.offset), size - 1);
@@ -346,7 +394,7 @@ LOG_WINDOW("Copying string for %d,%d from %p", row, column, window);
if (strSize > bufferSize || dst == NULL) {
newArray = env->NewCharArray(strSize);
env->SetCharArrayRegion(newArray, 0, strSize, (jchar const *)utf16.string());
- } else {
+ } else {
memcpy(dst, (jchar const *)utf16.string(), strSize * 2);
}
sizeCopied = strSize;
@@ -359,7 +407,7 @@ LOG_WINDOW("Copying string for %d,%d from %p", row, column, window);
memcpy(dst, (jchar const *)window->offsetToPtr(field.data.buffer.offset), size);
}
#endif
- }
+ }
} else if (type == FIELD_TYPE_INTEGER) {
int64_t value;
if (window->getLong(row, column, &value)) {
@@ -628,6 +676,9 @@ static JNINativeMethod sMethods[] =
{"putDouble_native", "(DII)Z", (void *)putDouble_native},
{"freeLastRow_native", "()V", (void *)freeLastRow},
{"putNull_native", "(II)Z", (void *)putNull_native},
+ {"isString_native", "(II)Z", (void *)isString_native},
+ {"isFloat_native", "(II)Z", (void *)isFloat_native},
+ {"isInteger_native", "(II)Z", (void *)isInteger_native},
};
int register_android_database_CursorWindow(JNIEnv * env)
@@ -646,7 +697,7 @@ int register_android_database_CursorWindow(JNIEnv * env)
LOGE("Error locating fields");
return -1;
}
-
+
clazz = env->FindClass("android/database/CharArrayBuffer");
if (clazz == NULL) {
LOGE("Can't find android/database/CharArrayBuffer");
diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp
index 66858f9..020aff4 100644
--- a/core/jni/android_database_SQLiteDatabase.cpp
+++ b/core/jni/android_database_SQLiteDatabase.cpp
@@ -28,7 +28,10 @@
#include <sqlite3.h>
#include <sqlite3_android.h>
#include <string.h>
-#include <utils.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <ctype.h>
#include <stdio.h>
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index c107993..31086b8 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -25,7 +25,7 @@
#include <ui/Surface.h>
#include <ui/Camera.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
using namespace android;
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 42ada54..0cce3a6 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -30,8 +30,8 @@
#include "media/AudioSystem.h"
#include "media/AudioTrack.h"
-#include <utils/MemoryHeapBase.h>
-#include <utils/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
// ----------------------------------------------------------------------------
diff --git a/core/jni/android_os_Exec.cpp b/core/jni/android_os_Exec.cpp
deleted file mode 100644
index ca5e695..0000000
--- a/core/jni/android_os_Exec.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "Exec"
-
-#include "JNIHelp.h"
-#include "jni.h"
-#include "utils/Log.h"
-#include "utils/misc.h"
-#include "android_runtime/AndroidRuntime.h"
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/wait.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <termios.h>
-
-namespace android
-{
-
-static jclass class_fileDescriptor;
-static jfieldID field_fileDescriptor_descriptor;
-static jmethodID method_fileDescriptor_init;
-
-
-static int create_subprocess(const char *cmd, const char *arg0, const char *arg1,
- int* pProcessId)
-{
- char *devname;
- int ptm;
- pid_t pid;
-
- ptm = open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
- if(ptm < 0){
- LOGE("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
- return -1;
- }
- fcntl(ptm, F_SETFD, FD_CLOEXEC);
-
- if(grantpt(ptm) || unlockpt(ptm) ||
- ((devname = (char*) ptsname(ptm)) == 0)){
- LOGE("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
- return -1;
- }
-
- pid = fork();
- if(pid < 0) {
- LOGE("- fork failed: %s -\n", strerror(errno));
- return -1;
- }
-
- if(pid == 0){
- int pts;
-
- setsid();
-
- pts = open(devname, O_RDWR);
- if(pts < 0) exit(-1);
-
- dup2(pts, 0);
- dup2(pts, 1);
- dup2(pts, 2);
-
- close(ptm);
-
- execl(cmd, cmd, arg0, arg1, NULL);
- exit(-1);
- } else {
- *pProcessId = (int) pid;
- return ptm;
- }
-}
-
-
-static jobject android_os_Exec_createSubProcess(JNIEnv *env, jobject clazz,
- jstring cmd, jstring arg0, jstring arg1, jintArray processIdArray)
-{
- const jchar* str = cmd ? env->GetStringCritical(cmd, 0) : 0;
- String8 cmd_8;
- if (str) {
- cmd_8 = String8(str, env->GetStringLength(cmd));
- env->ReleaseStringCritical(cmd, str);
- }
-
- str = arg0 ? env->GetStringCritical(arg0, 0) : 0;
- const char* arg0Str = 0;
- String8 arg0_8;
- if (str) {
- arg0_8 = String8(str, env->GetStringLength(arg0));
- env->ReleaseStringCritical(arg0, str);
- arg0Str = arg0_8.string();
- }
-
- str = arg1 ? env->GetStringCritical(arg1, 0) : 0;
- const char* arg1Str = 0;
- String8 arg1_8;
- if (str) {
- arg1_8 = String8(str, env->GetStringLength(arg1));
- env->ReleaseStringCritical(arg1, str);
- arg1Str = arg1_8.string();
- }
-
- int procId;
- int ptm = create_subprocess(cmd_8.string(), arg0Str, arg1Str, &procId);
-
- if (processIdArray) {
- int procIdLen = env->GetArrayLength(processIdArray);
- if (procIdLen > 0) {
- jboolean isCopy;
-
- int* pProcId = (int*) env->GetPrimitiveArrayCritical(processIdArray, &isCopy);
- if (pProcId) {
- *pProcId = procId;
- env->ReleasePrimitiveArrayCritical(processIdArray, pProcId, 0);
- }
- }
- }
-
- jobject result = env->NewObject(class_fileDescriptor, method_fileDescriptor_init);
-
- if (!result) {
- LOGE("Couldn't create a FileDescriptor.");
- }
- else {
- env->SetIntField(result, field_fileDescriptor_descriptor, ptm);
- }
-
- return result;
-}
-
-
-static void android_os_Exec_setPtyWindowSize(JNIEnv *env, jobject clazz,
- jobject fileDescriptor, jint row, jint col, jint xpixel, jint ypixel)
-{
- int fd;
- struct winsize sz;
-
- fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
- if (env->ExceptionOccurred() != NULL) {
- return;
- }
-
- sz.ws_row = row;
- sz.ws_col = col;
- sz.ws_xpixel = xpixel;
- sz.ws_ypixel = ypixel;
-
- ioctl(fd, TIOCSWINSZ, &sz);
-}
-
-static int android_os_Exec_waitFor(JNIEnv *env, jobject clazz,
- jint procId) {
- int status;
- waitpid(procId, &status, 0);
- int result = 0;
- if (WIFEXITED(status)) {
- result = WEXITSTATUS(status);
- }
- return result;
-}
-
-static JNINativeMethod method_table[] = {
- { "createSubprocess", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[I)Ljava/io/FileDescriptor;",
- (void*) android_os_Exec_createSubProcess },
- { "setPtyWindowSize", "(Ljava/io/FileDescriptor;IIII)V",
- (void*) android_os_Exec_setPtyWindowSize},
- { "waitFor", "(I)I",
- (void*) android_os_Exec_waitFor}
-};
-
-int register_android_os_Exec(JNIEnv *env)
-{
- class_fileDescriptor = env->FindClass("java/io/FileDescriptor");
-
- if (class_fileDescriptor == NULL) {
- LOGE("Can't find java/io/FileDescriptor");
- return -1;
- }
-
- field_fileDescriptor_descriptor = env->GetFieldID(class_fileDescriptor, "descriptor", "I");
-
- if (field_fileDescriptor_descriptor == NULL) {
- LOGE("Can't find FileDescriptor.descriptor");
- return -1;
- }
-
- method_fileDescriptor_init = env->GetMethodID(class_fileDescriptor, "<init>", "()V");
- if (method_fileDescriptor_init == NULL) {
- LOGE("Can't find FileDescriptor.init");
- return -1;
- }
-
- return AndroidRuntime::registerNativeMethods(
- env, "android/os/Exec",
- method_table, NELEM(method_table));
-}
-
-};
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 7325432..f0885fd 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -25,12 +25,12 @@
#include <stdio.h>
#include <utils/Atomic.h>
-#include <utils/IInterface.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
#include <utils/Log.h>
-#include <utils/Parcel.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <android_runtime/AndroidRuntime.h>
diff --git a/core/jni/android_util_Binder.h b/core/jni/android_util_Binder.h
index 16d993d..495e76a 100644
--- a/core/jni/android_util_Binder.h
+++ b/core/jni/android_util_Binder.h
@@ -15,7 +15,7 @@
** limitations under the License.
*/
-#include <utils/IBinder.h>
+#include <binder/IBinder.h>
#include "jni.h"
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 95c38dc..e8bffa4 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -18,9 +18,9 @@
#define LOG_TAG "Process"
#include <utils/Log.h>
-#include <utils/IPCThreadState.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <utils/String8.h>
#include <utils/Vector.h>
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 20cb34a..0498057 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -25,7 +25,7 @@
<!-- Permissions for things that cost money -->
<!-- ====================================== -->
<eat-comment />
-
+
<!-- Used for permissions that can be used to make the user spend money
without their direct involvement. For example, this is the group
for permissions that allow you to directly place phone calls,
@@ -54,7 +54,7 @@
<!-- Permissions for accessing messages -->
<!-- ================================== -->
<eat-comment />
-
+
<!-- Used for permissions that allow an application to send messages
on behalf of the user or intercept messages being received by the
user. This is primarily intended for SMS/MMS messaging, such as
@@ -104,7 +104,7 @@
<!-- Permissions for accessing personal info (contacts and calendar) -->
<!-- =============================================================== -->
<eat-comment />
-
+
<!-- Used for permissions that provide access to the user's private data,
such as contacts, calendar events, e-mail messages, etc. This includes
both reading and writing of this data (which should generally be
@@ -158,8 +158,8 @@
android:description="@string/permdesc_writeCalendar" />
<!-- Allows an application to read the user dictionary. This should
- really only be required by an IME, or a dictionary editor like
- the Settings app.
+ really only be required by an IME, or a dictionary editor like
+ the Settings app.
@hide Pending API council approval -->
<permission android:name="android.permission.READ_USER_DICTIONARY"
android:permissionGroup="android.permission-group.PERSONAL_INFO"
@@ -179,7 +179,7 @@
<!-- Permissions for accessing location info -->
<!-- ======================================= -->
<eat-comment />
-
+
<!-- Used for permissions that allow access to the user's current
location. -->
<permission-group android:name="android.permission-group.LOCATION"
@@ -224,7 +224,7 @@
<!-- Permissions for accessing networks -->
<!-- ======================================= -->
<eat-comment />
-
+
<!-- Used for permissions that provide access to networking services. The
main permission here is internet access, but this is also an
appropriate group for accessing or modifying any network configuration
@@ -265,7 +265,7 @@
<!-- Permissions for accessing accounts -->
<!-- ================================== -->
<eat-comment />
-
+
<!-- Permissions for direct access to Google accounts.
Note that while right now this is only used for Google accounts,
we expect in the future to have a more general account management
@@ -286,7 +286,7 @@
<!-- Permissions for accessing hardware -->
<!-- ================================== -->
<eat-comment />
-
+
<!-- Used for permissions that provide direct access to the hardware on
the device. This includes audio, the camera, vibrator, etc. -->
<permission-group android:name="android.permission-group.HARDWARE_CONTROLS"
@@ -339,7 +339,7 @@
<!-- Permissions associated with telephony state -->
<!-- =========================================== -->
<eat-comment />
-
+
<!-- Used for permissions that are associated with accessing and modifyign
telephony state: intercepting outgoing calls, reading
and modifying the phone state. Note that
@@ -393,7 +393,7 @@
<!-- Permissions for low-level system interaction -->
<!-- ============================================ -->
<eat-comment />
-
+
<!-- Group of permissions that are related to system APIs. Many
of these are not permissions the user will be expected to understand,
and such permissions should generally be marked as "normal" protection
@@ -617,7 +617,7 @@
android:description="@string/permdesc_writeApnSettings"
android:label="@string/permlab_writeApnSettings" />
- <!-- Allows an application to allow access the subscribed feeds
+ <!-- Allows an application to allow access the subscribed feeds
ContentProvider. -->
<permission android:name="android.permission.SUBSCRIBED_FEEDS_READ"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
@@ -629,7 +629,7 @@
android:label="@string/permlab_subscribedFeedsWrite"
android:description="@string/permdesc_subscribedFeedsWrite"
android:protectionLevel="dangerous" />
-
+
<!-- Allows applications to change network connectivity state -->
<permission android:name="android.permission.CHANGE_NETWORK_STATE"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
@@ -680,7 +680,7 @@
<!-- Permissions for special development tools -->
<!-- ========================================= -->
<eat-comment />
-
+
<!-- Group of permissions that are related to development features. These
are not permissions that should appear in normal applications; they
protect APIs that are intended only to be used for development
@@ -1036,6 +1036,11 @@
android:excludeFromRecents="true">
</activity>
+ <activity android:name="android.accounts.ChooseAccountActivity"
+ android:excludeFromRecents="true"
+ android:exported="true">
+ </activity>
+
<service android:name="com.android.server.LoadAverageService"
android:exported="true" />
@@ -1048,7 +1053,7 @@
<receiver android:name="com.android.server.MasterClearReceiver"
android:permission="android.permission.MASTER_CLEAR" >
<intent-filter>
- <action android:name="android.intent.action.GTALK_DATA_MESSAGE_RECEIVED" />
+ <action android:name="android.intent.action.REMOTE_INTENT" />
<category android:name="android.intent.category.MASTER_CLEAR" />
</intent-filter>
</receiver>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index cda7431..8c4b714 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4,9 +4,9 @@
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.
@@ -64,7 +64,7 @@
<!-- Inverse hint text color -->
<attr name="textColorHintInverse" format="reference|color" />
-
+
<!-- Bright text color. Only differentiates based on the disabled state. -->
<attr name="textColorPrimaryDisableOnly" format="reference|color" />
@@ -105,20 +105,20 @@
<!-- Text color, typeface, size, and style for the text inside of a button. -->
<attr name="textAppearanceButton" format="reference" />
-
+
<!-- A styled string, specifying the style to be used for showing
inline candidate text when composing with an input method. The
text itself will be ignored, but the style spans will be applied
to the candidate text as it is edited. -->
<attr name="candidatesTextStyleSpans" format="reference|string" />
-
+
<!-- Drawable to use for check marks -->
<attr name="textCheckMark" format="reference" />
<attr name="textCheckMarkInverse" format="reference" />
<!-- Drawable to use for multiple choice indicators-->
<attr name="listChoiceIndicatorMultiple" format="reference" />
-
+
<!-- Drawable to use for single choice indicators-->
<attr name="listChoiceIndicatorSingle" format="reference" />
@@ -143,7 +143,7 @@
<!-- Gallery styles -->
<!-- ============== -->
<eat-comment />
-
+
<!-- The preferred background for gallery items. This should be set
as the background of any Views you provide from the Adapter. -->
<attr name="galleryItemBackground" format="reference" />
@@ -163,20 +163,20 @@
<attr name="listSeparatorTextViewStyle" format="reference" />
<!-- The preferred left padding for an expandable list item (for child-specific layouts,
use expandableListPreferredChildPaddingLeft). This takes into account
- the indicator that will be shown to next to the item. -->
+ the indicator that will be shown to next to the item. -->
<attr name="expandableListPreferredItemPaddingLeft" format="dimension" />
<!-- The preferred left padding for an expandable list item that is a child.
- If this is not provided, it defaults to the expandableListPreferredItemPaddingLeft. -->
+ If this is not provided, it defaults to the expandableListPreferredItemPaddingLeft. -->
<attr name="expandableListPreferredChildPaddingLeft" format="dimension" />
<!-- The preferred left bound for an expandable list item's indicator. For a child-specific
- indicator, use expandableListPreferredChildIndicatorLeft. -->
+ indicator, use expandableListPreferredChildIndicatorLeft. -->
<attr name="expandableListPreferredItemIndicatorLeft" format="dimension" />
<!-- The preferred right bound for an expandable list item's indicator. For a child-specific
- indicator, use expandableListPreferredChildIndicatorRight. -->
+ indicator, use expandableListPreferredChildIndicatorRight. -->
<attr name="expandableListPreferredItemIndicatorRight" format="dimension" />
- <!-- The preferred left bound for an expandable list child's indicator. -->
+ <!-- The preferred left bound for an expandable list child's indicator. -->
<attr name="expandableListPreferredChildIndicatorLeft" format="dimension" />
- <!-- The preferred right bound for an expandable list child's indicator. -->
+ <!-- The preferred right bound for an expandable list child's indicator. -->
<attr name="expandableListPreferredChildIndicatorRight" format="dimension" />
<!-- ============= -->
@@ -225,7 +225,7 @@
any of the attributes defined by
{@link android.R.styleable#WindowAnimation}. -->
<attr name="windowAnimationStyle" format="reference" />
-
+
<!-- Defines the default soft input state that this window would
like when it is displayed. -->
<attr name="windowSoftInputMode">
@@ -247,7 +247,7 @@
<!-- Always make the soft input area visible when this window
has input focus. -->
<flag name="stateAlwaysVisible" value="5" />
-
+
<!-- The window resize/pan adjustment has not been specified,
the system will automatically select between resize and pan
modes, depending
@@ -274,7 +274,7 @@
use the window's theme to show a preview of it before your
actual instance is shown to the user. -->
<attr name="windowDisablePreview" format="boolean" />
-
+
<!-- Flag indicating that this window should not be displayed at all.
The default value is false; if set to true, and this window is
the main window of an Activity, then it will never actually
@@ -282,13 +282,13 @@
must immediately quit without waiting for user interaction,
because there will be no such interaction coming. -->
<attr name="windowNoDisplay" format="boolean" />
-
+
<!-- ============ -->
<!-- Alert Dialog styles -->
<!-- ============ -->
<eat-comment />
<attr name="alertDialogStyle" format="reference" />
-
+
<!-- ============ -->
<!-- Panel styles -->
<!-- ============ -->
@@ -387,7 +387,7 @@
<!-- Preference styles -->
<!-- =================== -->
<eat-comment />
-
+
<!-- Default style for PreferenceScreen. -->
<attr name="preferenceScreenStyle" format="reference" />
<!-- Default style for PreferenceCategory. -->
@@ -408,7 +408,7 @@
<attr name="ringtonePreferenceStyle" format="reference" />
<!-- The preference layout that has the child/tabbed effect. -->
<attr name="preferenceLayoutChild" format="reference" />
-
+
</declare-styleable>
<!-- **************************************************************** -->
@@ -426,7 +426,7 @@
</ul>
-->
<attr name="textSize" format="dimension" />
-
+
<!-- Default text typeface. -->
<attr name="typeface">
<enum name="normal" value="0" />
@@ -434,26 +434,26 @@
<enum name="serif" value="2" />
<enum name="monospace" value="3" />
</attr>
-
+
<!-- Default text typeface style. -->
<attr name="textStyle">
<flag name="normal" value="0" />
<flag name="bold" value="1" />
<flag name="italic" value="2" />
</attr>
-
+
<!-- Color of text (usually same as colorForeground). -->
<attr name="textColor" format="reference|color" />
-
+
<!-- Color of highlighted text. -->
<attr name="textColorHighlight" format="reference|color" />
-
+
<!-- Color of hint text (displayed when the field is empty). -->
<attr name="textColorHint" format="reference|color" />
-
+
<!-- Color of link text (URLs). -->
<attr name="textColorLink" format="reference|color" />
-
+
<!-- Where to ellipsize text. -->
<attr name="ellipsize">
<enum name="none" value="0" />
@@ -462,7 +462,7 @@
<enum name="end" value="3" />
<enum name="marquee" value="4" />
</attr>
-
+
<!-- The type of data being placed in a text field, used to help an
input method decide how to let the user enter text. The constants
here correspond to those defined by
@@ -774,11 +774,11 @@
<!-- ========================== -->
<eat-comment />
- <!-- This enum provides the same keycode values as can be found in
+ <!-- This enum provides the same keycode values as can be found in
{@link android.view.KeyEvent} -->
<attr name="keycode">
<enum name="KEYCODE_UNKNOWN" value="0" />
- <enum name="KEYCODE_SOFT_LEFT" value="1" />
+ <enum name="KEYCODE_SOFT_LEFT" value="1" />
<enum name="KEYCODE_SOFT_RIGHT" value="2" />
<enum name="KEYCODE_HOME" value="3" />
<enum name="KEYCODE_BACK" value="4" />
@@ -911,7 +911,7 @@
<attr name="bottomMedium" format="reference|color" />
<attr name="centerMedium" format="reference|color" />
</declare-styleable>
-
+
<!-- Window animation class attributes. -->
<declare-styleable name="WindowAnimation">
<!-- The animation used when a window is being added. -->
@@ -955,7 +955,7 @@
allows you to later retrieve the view
with <code>findViewById(R.id.my_id)</code>. -->
<attr name="id" format="reference" />
-
+
<!-- Supply a tag for this view containing a String, to be retrieved
later with {@link android.view.View#getTag View.getTag()} or
searched for with {@link android.view.View#findViewWithTag
@@ -963,7 +963,7 @@
IDs (through the android:id attribute) instead of tags because
they are faster and allow for compile-time type checking. -->
<attr name="tag" format="string" />
-
+
<!-- The initial horizontal scroll offset, in pixels.-->
<attr name="scrollX" format="dimension" />
@@ -977,7 +977,7 @@
<attr name="background" format="reference|color" />
<!-- Sets the padding, in pixels, of all four edges. Padding is defined as
- space between the edges of the view and the view's content. A views size
+ space between the edges of the view and the view's content. A views size
will include it's padding. If a {@link android.R.attr#background}
is provided, the padding will initially be set to that (0 if the
drawable does not have padding). Explicitly setting a padding value
@@ -1032,12 +1032,12 @@
</attr>
<!-- Controls the scrollbar style and position. The scrollbars can be overlaid or
- inset. When inset, they add to the padding of the view. And the
- scrollbars can be drawn inside the padding area or on the edge of
- the view. For example, if a view has a background drawable and you
- want to draw the scrollbars inside the padding specified by the
- drawable, you can use insideOverlay or insideInset. If you want them
- to appear at the edge of the view, ignoring the padding, then you can
+ inset. When inset, they add to the padding of the view. And the
+ scrollbars can be drawn inside the padding area or on the edge of
+ the view. For example, if a view has a background drawable and you
+ want to draw the scrollbars inside the padding specified by the
+ drawable, you can use insideOverlay or insideInset. If you want them
+ to appear at the edge of the view, ignoring the padding, then you can
use outsideOverlay or outsideInset.-->
<attr name="scrollbarStyle">
<!-- Inside the padding and overlaid -->
@@ -1049,14 +1049,14 @@
<!-- Edge of the view and inset -->
<enum name="outsideInset" value="0x03000000" />
</attr>
-
+
<!-- Set this if the view will serve as a scrolling container, meaing
that it can be resized to shrink its overall window so that there
will be space for an input method. If not set, the default
value will be true if "scrollbars" has the vertical scrollbar
set, else it will be false. -->
<attr name="isScrollContainer" format="boolean" />
-
+
<!-- Sets the width of vertical scrollbars and height of horizontal scrollbars. -->
<attr name="scrollbarSize" format="dimension" />
<!-- Defines the horizontal scrollbar thumb drawable. -->
@@ -1118,10 +1118,10 @@
<!-- Defines whether this view reacts to click events. -->
<attr name="clickable" format="boolean" />
-
+
<!-- Defines whether this view reacts to long click events. -->
<attr name="longClickable" format="boolean" />
-
+
<!-- If unset, no state will be saved for this view when it is being
frozen. The default is true, allowing the view to be saved
(however it also must have an ID assigned to it for its
@@ -1129,7 +1129,7 @@
state for this view, not for its children which may still
be saved. -->
<attr name="saveEnabled" format="boolean" />
-
+
<!-- Defines the quality of translucent drawing caches. This property is used
only when the drawing cache is enabled and translucent. The default value is auto. -->
<attr name="drawingCacheQuality">
@@ -1147,16 +1147,16 @@
<!-- Controls whether the view's window should keep the screen on
while visible. -->
<attr name="keepScreenOn" format="boolean" />
-
+
<!-- When this attribute is set to true, the view gets its drawable state
(focused, pressed, etc.) from its direct parent rather than from itself. -->
<attr name="duplicateParentState" format="boolean" />
-
+
<!-- Defines the minimum height of the view. It is not guaranteed
the view will be able to achieve this minimum height (for example,
if its parent layout constrains it with less available height). -->
<attr name="minHeight" />
-
+
<!-- Defines the minimum width of the view. It is not guaranteed
the view will be able to achieve this minimum width (for example,
if its parent layout constrains it with less available width). -->
@@ -1218,7 +1218,7 @@
<flag name="animation" value="0x1" />
<!-- The drawing cache is persisted after a scroll. -->
<flag name="scrolling" value="0x2" />
- <!-- The drawing cache is always persisted. -->
+ <!-- The drawing cache is always persisted. -->
<flag name="all" value="0x3" />
</attr>
<!-- Defines whether the ViewGroup should always draw its children using their
@@ -1331,7 +1331,7 @@
method should be considered an option as the default. -->
<attr name="isDefault" format="boolean" />
</declare-styleable>
-
+
<!-- =============================== -->
<!-- Widget package class attributes -->
<!-- =============================== -->
@@ -1340,7 +1340,7 @@
<declare-styleable name="AbsListView">
<!-- Drawable used to indicate the currently selected item in the list. -->
<attr name="listSelector" format="color|reference" />
- <!-- When set to true, the selector will be drawn over the selected item.
+ <!-- When set to true, the selector will be drawn over the selected item.
Otherwise the selector is drawn behind the selected item. The default
value is false. -->
<attr name="drawSelectorOnTop" format="boolean" />
@@ -1363,13 +1363,13 @@
already visible on screen. -->
<enum name="normal" value="1" />
<!-- The list will automatically scroll to the bottom, no matter what items
- are currently visible. -->
+ are currently visible. -->
<enum name="alwaysScroll" value="2" />
</attr>
<!-- Indicates that this list will always be drawn on top of solid, single-color
opaque background. This allows the list to optimize drawing. -->
<attr name="cacheColorHint" format="color" />
- <!-- Enables the fast scroll thumb that can be dragged to quickly scroll through
+ <!-- Enables the fast scroll thumb that can be dragged to quickly scroll through
the list. -->
<attr name="fastScrollEnabled" format="boolean" />
<!-- When set to true, the list will use a more refined calculation
@@ -1471,7 +1471,7 @@
<!-- Defines whether the foreground drawable should be drawn inside the padding.
This property is turned on by default. -->
<attr name="foregroundInsidePadding" format="boolean" />
- <!-- Determines whether to measure all children or just those in
+ <!-- Determines whether to measure all children or just those in
the VISIBLE or INVISIBLE state when measuring. Defaults to false. -->
<attr name="measureAllChildren" format="boolean" />
</declare-styleable>
@@ -1481,14 +1481,14 @@
<!-- Indicator shown beside the child View. This can be a stateful Drawable. -->
<attr name="childIndicator" format="reference" />
<!-- The left bound for an item's indicator. To specify a left bound specific to children,
- use childIndicatorLeft. -->
+ use childIndicatorLeft. -->
<attr name="indicatorLeft" format="dimension" />
<!-- The right bound for an item's indicator. To specify a right bound specific to children,
- use childIndicatorRight. -->
+ use childIndicatorRight. -->
<attr name="indicatorRight" format="dimension" />
- <!-- The left bound for a child's indicator. -->
+ <!-- The left bound for a child's indicator. -->
<attr name="childIndicatorLeft" format="dimension" />
- <!-- The right bound for a child's indicator. -->
+ <!-- The right bound for a child's indicator. -->
<attr name="childIndicatorRight" format="dimension" />
<!-- Drawable or color that is used as a divider for children. (It will drawn
below and above child items.) The height of this will be the same as
@@ -1539,10 +1539,10 @@
<!-- Set this to true if you want the ImageView to adjust its bounds
to preserve the aspect ratio of its drawable. -->
<attr name="adjustViewBounds" format="boolean" />
- <!-- An optional argument to supply a maximum width for this view.
+ <!-- An optional argument to supply a maximum width for this view.
See {see android.widget.ImageView#setMaxWidth} for details. -->
<attr name="maxWidth" format="dimension" />
- <!-- An optional argument to supply a maximum height for this view.
+ <!-- An optional argument to supply a maximum height for this view.
See {see android.widget.ImageView#setMaxHeight} for details. -->
<attr name="maxHeight" format="dimension" />
<!-- Set a tinting color for the image -->
@@ -1598,7 +1598,7 @@
<attr name="dividerHeight" format="dimension" />
<!-- Defines the choice behavior for the ListView. By default, lists do not have
any choice behavior. By setting the choiceMode to singleChoice, the List
- allows up to one item to be in a chosen state. By setting the choiceMode to
+ allows up to one item to be in a chosen state. By setting the choiceMode to
multipleChoice, the list allows any number of items to be chosen. -->
<attr name="choiceMode">
<!-- Normal list that does not indicate choices -->
@@ -1643,7 +1643,7 @@
<!-- 'More' icon -->
<attr name="moreIcon" format="reference" />
</declare-styleable>
-
+
<declare-styleable name="ProgressBar">
<!-- Defines the maximum value the progress can take. -->
<attr name="max" format="integer" />
@@ -1676,27 +1676,27 @@
<attr name="maxWidth" />
<attr name="minHeight" format="dimension" />
<attr name="maxHeight" />
- <attr name="interpolator" format="reference" />
+ <attr name="interpolator" format="reference" />
</declare-styleable>
-
+
<declare-styleable name="SeekBar">
- <!-- Draws the thumb on a seekbar -->
+ <!-- Draws the thumb on a seekbar -->
<attr name="thumb" format="reference" />
<!-- An offset for the thumb that allows it to extend out of the range of the track. -->
- <attr name="thumbOffset" format="dimension" />
+ <attr name="thumbOffset" format="dimension" />
</declare-styleable>
-
+
<declare-styleable name="RatingBar">
- <!-- The number of stars (or rating items) to show. -->
- <attr name="numStars" format="integer" />
- <!-- The rating to set by default. -->
- <attr name="rating" format="float" />
- <!-- The step size of the rating. -->
- <attr name="stepSize" format="float" />
- <!-- Whether this rating bar is an indicator (and non-changeable by the user). -->
- <attr name="isIndicator" format="boolean" />
- </declare-styleable>
-
+ <!-- The number of stars (or rating items) to show. -->
+ <attr name="numStars" format="integer" />
+ <!-- The rating to set by default. -->
+ <attr name="rating" format="float" />
+ <!-- The step size of the rating. -->
+ <attr name="stepSize" format="float" />
+ <!-- Whether this rating bar is an indicator (and non-changeable by the user). -->
+ <attr name="isIndicator" format="boolean" />
+ </declare-styleable>
+
<declare-styleable name="RadioGroup">
<!-- The id of the child radio button that should be checked by default
within this radio group. -->
@@ -1718,7 +1718,7 @@
indices are ignored. You can shrink all columns by using the
value "*" instead. Note that a column can be marked stretchable
and shrinkable at the same time. -->
- <attr name="shrinkColumns" format="string" />
+ <attr name="shrinkColumns" format="string" />
<!-- The 0 based index of the columns to collapse. The column indices
must be separated by a comma: 1, 2, 5. Illegal and duplicate
indices are ignored. -->
@@ -1819,7 +1819,7 @@
<attr name="minEms" format="integer" min="0" />
<!-- Makes the TextView be at least this many pixels wide -->
<attr name="minWidth" />
- <!-- Specifies how to align the text by the view's x and/or y axis
+ <!-- Specifies how to align the text by the view's x and/or y axis
when the text is smaller than the view. -->
<attr name="gravity" />
<!-- Whether the text is allowed to be wider than the view (and
@@ -1837,10 +1837,10 @@
attribute. (If both singleLine and inputType are supplied,
the inputType flags will override the value of singleLine.)
{@deprecated This attribute is deprecated and is replaced by the textMultiLine flag
- in the inputType attribute. Use caution when altering existing layouts, as the
- default value of singeLine is false (multi-line mode), but if you specify any
- value for inputType, the default is single-line mode. (If both singleLine and
- inputType attributes are found, the inputType flags will override the value of
+ in the inputType attribute. Use caution when altering existing layouts, as the
+ default value of singeLine is false (multi-line mode), but if you specify any
+ value for inputType, the default is single-line mode. (If both singleLine and
+ inputType attributes are found, the inputType flags will override the value of
singleLine.) } -->
<attr name="singleLine" format="boolean" />
<!-- {@deprecated Use state_enabled instead.} -->
@@ -1944,7 +1944,7 @@
<attr name="lineSpacingExtra" format="dimension" />
<!-- Extra spacing between lines of text, as a multiplier. -->
<attr name="lineSpacingMultiplier" format="float" />
- <!-- The number of times to repeat the marquee animation. Only applied if the
+ <!-- The number of times to repeat the marquee animation. Only applied if the
TextView has marquee enabled. -->
<attr name="marqueeRepeatLimit" format="integer">
<!-- Indicates that marquee should repeat indefinitely -->
@@ -2035,7 +2035,7 @@
<!-- The prompt to display when the spinner's dialog is shown. -->
<attr name="prompt" format="reference" />
</declare-styleable>
- <declare-styleable name="DatePicker">
+ <declare-styleable name="DatePicker">
<!-- The first year (inclusive) i.e. 1940 -->
<attr name="startYear" format="integer" />
<!-- The last year (inclusive) i.e. 2010 -->
@@ -2197,7 +2197,7 @@
{@link android.graphics.drawable.Drawable#setVisible} -->
<attr name="visible" format="boolean" />
</declare-styleable>
-
+
<declare-styleable name="StateListDrawable">
<attr name="visible" />
<!-- If true, allows the drawable's padding to change based on the
@@ -2213,7 +2213,7 @@
current state. -->
<attr name="constantSize" format="boolean" />
</declare-styleable>
-
+
<declare-styleable name="AnimationDrawable">
<attr name="visible" />
<attr name="variablePadding" />
@@ -2222,15 +2222,15 @@
restarting at the first frame after the last has finished. -->
<attr name="oneshot" format="boolean" />
</declare-styleable>
-
+
<declare-styleable name="AnimationDrawableItem">
<!-- Amount of time (in milliseconds) to display this frame. -->
- <attr name="duration" format="integer" />
+ <attr name="duration" format="integer" />
<!-- Reference to a drawable resource to use for the frame. If not
given, the drawable must be defined by the first child tag. -->
<attr name="drawable" format="reference" />
</declare-styleable>
-
+
<declare-styleable name="GradientDrawable">
<attr name="visible" />
<attr name="shape">
@@ -2253,18 +2253,18 @@
<attr name="thickness" format="dimension" />
<attr name="useLevel" />
</declare-styleable>
-
+
<declare-styleable name="GradientDrawableSize">
<attr name="width" />
<attr name="height" />
</declare-styleable>
-
+
<declare-styleable name="GradientDrawableGradient">
<attr name="startColor" format="color" />
<!-- Optional center color. For linear gradients, use centerX or centerY to place the center color. -->
<attr name="centerColor" format="color" />
<attr name="endColor" format="color" />
- <attr name="useLevel" format="boolean" />
+ <attr name="useLevel" format="boolean" />
<attr name="angle" format="float" />
<attr name="type">
<enum name="linear" value="0" />
@@ -2275,18 +2275,18 @@
<attr name="centerY" format="float|fraction" />
<attr name="gradientRadius" format="float|fraction" />
</declare-styleable>
-
+
<declare-styleable name="GradientDrawableSolid">
<attr name="color" format="color" />
</declare-styleable>
-
+
<declare-styleable name="GradientDrawableStroke">
<attr name="width" />
<attr name="color" />
<attr name="dashWidth" format="dimension" />
<attr name="dashGap" format="dimension" />
</declare-styleable>
-
+
<declare-styleable name="DrawableCorners">
<attr name="radius" format="dimension" />
<attr name="topLeftRadius" format="dimension" />
@@ -2294,14 +2294,14 @@
<attr name="bottomLeftRadius" format="dimension" />
<attr name="bottomRightRadius" format="dimension" />
</declare-styleable>
-
+
<declare-styleable name="GradientDrawablePadding">
<attr name="left" format="dimension" />
<attr name="top" format="dimension" />
<attr name="right" format="dimension" />
<attr name="bottom" format="dimension" />
</declare-styleable>
-
+
<declare-styleable name="LayerDrawableItem">
<attr name="left" />
<attr name="top" />
@@ -2310,7 +2310,7 @@
<attr name="drawable" />
<attr name="id" />
</declare-styleable>
-
+
<declare-styleable name="LevelListDrawableItem">
<!-- The minimum level allowed for this item. -->
<attr name="minLevel" format="integer" />
@@ -2318,7 +2318,7 @@
<attr name="maxLevel" format="integer" />
<attr name="drawable" />
</declare-styleable>
-
+
<declare-styleable name="RotateDrawable">
<attr name="visible" />
<attr name="fromDegrees" format="float" />
@@ -2474,7 +2474,7 @@
<declare-styleable name="AnimationSet">
<attr name="shareInterpolator" format="boolean" />
</declare-styleable>
-
+
<declare-styleable name="Animation">
<!-- Defines the interpolator used to smooth the animation movement in time. -->
<attr name="interpolator" />
@@ -2517,14 +2517,14 @@
<enum name="bottom" value="-1" />
</attr>
</declare-styleable>
-
+
<declare-styleable name="RotateAnimation">
<attr name="fromDegrees" />
<attr name="toDegrees" />
<attr name="pivotX" />
<attr name="pivotY" />
</declare-styleable>
-
+
<declare-styleable name="ScaleAnimation">
<attr name="fromXScale" format="float" />
<attr name="toXScale" format="float" />
@@ -2533,14 +2533,14 @@
<attr name="pivotX" />
<attr name="pivotY" />
</declare-styleable>
-
+
<declare-styleable name="TranslateAnimation">
<attr name="fromXDelta" format="float|fraction" />
<attr name="toXDelta" format="float|fraction" />
<attr name="fromYDelta" format="float|fraction" />
<attr name="toYDelta" format="float|fraction" />
</declare-styleable>
-
+
<declare-styleable name="AlphaAnimation">
<attr name="fromAlpha" format="float" />
<attr name="toAlpha" format="float" />
@@ -2602,12 +2602,12 @@
<!-- This is the amount of deceleration to add when easing in. -->
<attr name="factor" format="float" />
</declare-styleable>
-
+
<declare-styleable name="DecelerateInterpolator">
<!-- This is the amount of acceleration to add when easing out. -->
<attr name="factor" />
</declare-styleable>
-
+
<declare-styleable name="CycleInterpolator">
<attr name="cycles" format="float" />
</declare-styleable>
@@ -2717,18 +2717,18 @@
</declare-styleable>
<!-- State array representing an expandable list child's indicator. -->
<declare-styleable name="ExpandableListChildIndicatorState">
- <!-- State identifier indicating the child is the last child within its group. -->
+ <!-- State identifier indicating the child is the last child within its group. -->
<attr name="state_last" />
</declare-styleable>
<!-- State array representing an expandable list group's indicator. -->
<declare-styleable name="ExpandableListGroupIndicatorState">
- <!-- State identifier indicating the group is expanded. -->
+ <!-- State identifier indicating the group is expanded. -->
<attr name="state_expanded" format="boolean" />
- <!-- State identifier indicating the group is empty (has no children). -->
+ <!-- State identifier indicating the group is empty (has no children). -->
<attr name="state_empty" format="boolean" />
</declare-styleable>
<declare-styleable name="PopupWindowBackgroundState">
- <!-- State identifier indicating the popup will be above the anchor. -->
+ <!-- State identifier indicating the popup will be above the anchor. -->
<attr name="state_above_anchor" format="boolean" />
</declare-styleable>
@@ -2738,7 +2738,7 @@
<eat-comment />
<!-- Searchable activities and applications must provide search configuration information
- in an XML file, typically called searchable.xml. This file is referenced in your manifest.
+ in an XML file, typically called searchable.xml. This file is referenced in your manifest.
For a more in-depth discussion of search configuration, please refer to
{@link android.app.SearchManager}. -->
<declare-styleable name="Searchable">
@@ -2747,29 +2747,29 @@
plain text. This is a reference to a drawable (icon) resource.
<i>Optional attribute.</i> -->
<attr name="icon" />
- <!-- This is the user-displayed name of the searchable activity. <i>Required
+ <!-- This is the user-displayed name of the searchable activity. <i>Required
attribute.</i> -->
<attr name="label" />
- <!-- If supplied, this string will be displayed as a hint to the user. <i>Optional
+ <!-- If supplied, this string will be displayed as a hint to the user. <i>Optional
attribute.</i> -->
<attr name="hint" />
<!-- If supplied, this string will be displayed as the text of the "Search" button.
- <i>Optional attribute.</i>
+ <i>Optional attribute.</i>
{@deprecated This will create a non-standard UI appearance, because the search bar UI is
changing to use only icons for its buttons.}-->
<attr name="searchButtonText" format="string" />
<attr name="inputType" />
<attr name="imeOptions" />
-
+
<!-- Additional features are controlled by mode bits in this field. Omitting
- this field, or setting to zero, provides default behavior. <i>Optional attribute.</i>
+ this field, or setting to zero, provides default behavior. <i>Optional attribute.</i>
-->
<attr name="searchMode">
<!-- If set, this flag enables the display of the search target (label) within the
search bar. If neither bad mode is selected, no badge will be shown. -->
<flag name="showSearchLabelAsBadge" value="0x04" />
<!-- If set, this flag enables the display of the search target (icon) within the
- search bar. (Note, overrides showSearchLabel) If neither bad mode is selected,
+ search bar. (Note, overrides showSearchLabel) If neither bad mode is selected,
no badge will be shown.-->
<flag name="showSearchIconAsBadge" value="0x08" />
<!-- If set, this flag causes the suggestion column SUGGEST_COLUMN_INTENT_DATA to
@@ -2783,11 +2783,11 @@
values are not suitable for user inspection and editing. -->
<flag name="queryRewriteFromText" value="0x20" />
</attr>
-
+
<!-- Voice search features are controlled by mode bits in this field. Omitting
this field, or setting to zero, provides default behavior.
If showVoiceSearchButton is set, then launchWebSearch or launchRecognizer must
- also be set. <i>Optional attribute.</i>
+ also be set. <i>Optional attribute.</i>
-->
<attr name="voiceSearchMode">
<!-- If set, display a voice search button. This only takes effect if voice search is
@@ -2806,9 +2806,9 @@
</attr>
<!-- If provided, this specifies the language model that should be used by the
- voice recognition system. See
- {@link android.speech.RecognizerIntent#EXTRA_LANGUAGE_MODEL } for more information.
- If not provided, the default value
+ voice recognition system. See
+ {@link android.speech.RecognizerIntent#EXTRA_LANGUAGE_MODEL } for more information.
+ If not provided, the default value
{@link android.speech.RecognizerIntent#LANGUAGE_MODEL_FREE_FORM } will be used. -->
<attr name="voiceLanguageModel" format="string" />
<!-- If provided, this specifies a prompt that will be displayed during voice input. -->
@@ -2818,14 +2818,14 @@
<attr name="voiceLanguage" format="string" />
<!-- If provided, enforces the maximum number of results to return, including the "best"
result which will always be provided as the SEARCH intent's primary query. Must be one
- or greater. If not provided, the recognizer will choose how many results to return.
+ or greater. If not provided, the recognizer will choose how many results to return.
-->
<attr name="voiceMaxResults" format="integer" />
<!-- If provided, this is the trigger indicating that the searchable activity
provides suggestions as well. The value must be a fully-qualified content provider
- authority (e.g. "com.example.android.apis.SuggestionProvider") and should match the
- "android:authorities" tag in your content provider's manifest entry. <i>Optional
+ authority (e.g. "com.example.android.apis.SuggestionProvider") and should match the
+ "android:authorities" tag in your content provider's manifest entry. <i>Optional
attribute.</i> -->
<attr name="searchSuggestAuthority" format="string" />
<!-- If provided, this will be inserted in the suggestions query Uri, after the authority
@@ -2833,19 +2833,19 @@
-->
<attr name="searchSuggestPath" format="string" />
<!-- If provided, suggestion queries will be passed into your query function
- as the <i>selection</i> parameter. Typically this will be a WHERE clause for your
- database, and will contain a single question mark, which represents the actual query
+ as the <i>selection</i> parameter. Typically this will be a WHERE clause for your
+ database, and will contain a single question mark, which represents the actual query
string that has been typed by the user. If not provided, then the user query text
- will be appended to the query Uri (after an additional "/".) <i>Optional
+ will be appended to the query Uri (after an additional "/".) <i>Optional
attribute.</i> -->
<attr name="searchSuggestSelection" format="string" />
- <!-- If provided, and not overridden by an action in the selected suggestion, this
+ <!-- If provided, and not overridden by an action in the selected suggestion, this
string will be placed in the action field of the {@link android.content.Intent Intent}
when the user clicks a suggestion. <i>Optional attribute.</i> -->
<attr name="searchSuggestIntentAction" format="string" />
- <!-- If provided, and not overridden by an action in the selected suggestion, this
- string will be placed in the data field of the {@link android.content.Intent Intent}
+ <!-- If provided, and not overridden by an action in the selected suggestion, this
+ string will be placed in the data field of the {@link android.content.Intent Intent}
when the user clicks a suggestion. <i>Optional attribute.</i> -->
<attr name="searchSuggestIntentData" format="string" />
@@ -2867,70 +2867,70 @@
<declare-styleable name="SearchableActionKey">
<!-- This attribute denotes the action key you wish to respond to. Note that not
all action keys are actually supported using this mechanism, as many of them are
- used for typing, navigation, or system functions. This will be added to the
+ used for typing, navigation, or system functions. This will be added to the
{@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to your
- searchable activity. To examine the key code, use
+ searchable activity. To examine the key code, use
{@link android.content.Intent#getIntExtra getIntExtra(SearchManager.ACTION_KEY)}.
- <p>Note, in addition to the keycode, you must also provide one or more of the action
+ <p>Note, in addition to the keycode, you must also provide one or more of the action
specifier attributes. <i>Required attribute.</i> -->
<attr name="keycode" />
-
+
<!-- If you wish to handle an action key during normal search query entry, you
- must define an action string here. This will be added to the
+ must define an action string here. This will be added to the
{@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to your
- searchable activity. To examine the string, use
+ searchable activity. To examine the string, use
{@link android.content.Intent#getStringExtra getStringExtra(SearchManager.ACTION_MSG)}.
<i>Optional attribute.</i> -->
<attr name="queryActionMsg" format="string" />
-
+
<!-- If you wish to handle an action key while a suggestion is being displayed <i>and
selected</i>, there are two ways to handle this. If <i>all</i> of your suggestions
- can handle the action key, you can simply define the action message using this
- attribute. This will be added to the
+ can handle the action key, you can simply define the action message using this
+ attribute. This will be added to the
{@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to your
- searchable activity. To examine the string, use
+ searchable activity. To examine the string, use
{@link android.content.Intent#getStringExtra getStringExtra(SearchManager.ACTION_MSG)}.
<i>Optional attribute.</i> -->
<attr name="suggestActionMsg" format="string" />
-
+
<!-- If you wish to handle an action key while a suggestion is being displayed <i>and
- selected</i>, but you do not wish to enable this action key for every suggestion,
+ selected</i>, but you do not wish to enable this action key for every suggestion,
then you can use this attribute to control it on a suggestion-by-suggestion basis.
- First, you must define a column (and name it here) where your suggestions will include
+ First, you must define a column (and name it here) where your suggestions will include
the action string. Then, in your content provider, you must provide this column, and
when desired, provide data in this column.
- The search manager will look at your suggestion cursor, using the string
- provided here in order to select a column, and will use that to select a string from
- the cursor. That string will be added to the
- {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to
- your searchable activity. To examine the string, use
- {@link android.content.Intent#getStringExtra
+ The search manager will look at your suggestion cursor, using the string
+ provided here in order to select a column, and will use that to select a string from
+ the cursor. That string will be added to the
+ {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to
+ your searchable activity. To examine the string, use
+ {@link android.content.Intent#getStringExtra
getStringExtra(SearchManager.ACTION_MSG)}. <i>If the data does not exist for the
selection suggestion, the action key will be ignored.</i><i>Optional attribute.</i> -->
<attr name="suggestActionMsgColumn" format="string" />
</declare-styleable>
-
+
<!-- ***************************************************************** -->
<!-- Support for MapView. -->
<!-- ***************************************************************** -->
<eat-comment />
-
+
<!-- The set of attributes for a MapView. -->
<declare-styleable name="MapView">
<!-- Value is a string that specifies the Maps API Key to use. -->
<attr name="apiKey" format="string" />
</declare-styleable>
-
+
<!-- **************************************************************** -->
<!-- Menu XML inflation. -->
<!-- **************************************************************** -->
<eat-comment />
-
+
<!-- Base attributes that are available to all Menu objects. -->
<declare-styleable name="Menu">
</declare-styleable>
-
+
<!-- Base attributes that are available to all groups. -->
<declare-styleable name="MenuGroup">
@@ -2949,11 +2949,11 @@
<!-- Items are alternative actions. -->
<enum name="alternative" value="0x00040000" />
</attr>
-
+
<!-- The order within the category applied to all items within this group.
(This will be or'ed with the category attribute.) -->
<attr name="orderInCategory" format="integer" />
-
+
<!-- Whether the items are capable of displaying a check mark. -->
<attr name="checkableBehavior">
<!-- The items are not checkable. -->
@@ -2964,7 +2964,7 @@
this group. -->
<enum name="single" value="2" />
</attr>
-
+
<!-- Whether the items are shown/visible. -->
<attr name="visible" />
@@ -2978,7 +2978,7 @@
<!-- The ID of the item. -->
<attr name="id" />
-
+
<!-- The category applied to the item.
(This will be or'ed with the orderInCategory attribute.) -->
<attr name="menuCategory" />
@@ -2989,15 +2989,15 @@
<!-- The title associated with the item. -->
<attr name="title" format="string" />
-
+
<!-- The condensed title associated with the item. This is used in situations where the
normal title may be too long to be displayed. -->
<attr name="titleCondensed" format="string" />
<!-- The icon associated with this item. This icon will not always be shown, so
- the title should be sufficient in describing this item. -->
+ the title should be sufficient in describing this item. -->
<attr name="icon" />
-
+
<!-- The alphabetic shortcut key. This is the shortcut when using a keyboard
with alphabetic keys. -->
<attr name="alphabeticShortcut" format="string" />
@@ -3005,14 +3005,14 @@
<!-- The numeric shortcut key. This is the shortcut when using a numeric (e.g., 12-key)
keyboard. -->
<attr name="numericShortcut" format="string" />
-
+
<!-- Whether the item is capable of displaying a check mark. -->
<attr name="checkable" format="boolean" />
-
- <!-- Whether the item is checked. Note that you must first have enabled checking with
+
+ <!-- Whether the item is checked. Note that you must first have enabled checking with
the checkable attribute or else the check mark will not appear. -->
<attr name="checked" />
-
+
<!-- Whether the item is shown/visible. -->
<attr name="visible" />
@@ -3038,7 +3038,7 @@
with a View's attributes. Some subclasses (e.g., EditTextPreference)
proxy all attributes to its EditText widget. -->
<eat-comment />
-
+
<!-- Base attributes available to Preference. -->
<declare-styleable name="Preference">
<!-- The key to store the Preference value. -->
@@ -3167,7 +3167,7 @@
it had previously been shown. -->
<attr name="imeExtractExitAnimation" format="reference" />
</declare-styleable>
-
+
<declare-styleable name="KeyboardView">
<!-- Default KeyboardView style. -->
<attr name="keyboardViewStyle" format="reference" />
@@ -3200,13 +3200,13 @@
<!-- Layout resource for popup keyboards -->
<attr name="popupLayout" format="reference" />
-
+
<attr name="shadowColor" />
<attr name="shadowRadius" />
</declare-styleable>
-
+
<declare-styleable name="KeyboardViewPreviewState">
- <!-- State for {@link android.inputmethodservice.KeyboardView KeyboardView}
+ <!-- State for {@link android.inputmethodservice.KeyboardView KeyboardView}
key preview background -->
<attr name="state_long_pressable" format="boolean" />
</declare-styleable>
@@ -3289,7 +3289,33 @@
If not supplied, then no activity will be launched. -->
<attr name="configure" format="string" />
</declare-styleable>
-
-
+
+
+ <!-- =============================== -->
+ <!-- Accounts package class attributes -->
+ <!-- =============================== -->
+
+ <!-- Use <code>account-authenticator</code> as the root tag of the XML resource that
+ describes an account authenticator.
+ -->
+ <declare-styleable name="AccountAuthenticator">
+ <!-- the account type this authenticator handles. -->
+ <attr name="accountType" format="string"/>
+ </declare-styleable>
+
+ <!-- =============================== -->
+ <!-- Accounts package class attributes -->
+ <!-- =============================== -->
+
+ <!-- Use <code>account-authenticator</code> as the root tag of the XML resource that
+ describes an account authenticator.
+ -->
+ <declare-styleable name="SyncAdapter">
+ <!-- the authority of a content provider. -->
+ <attr name="contentAuthority" format="string"/>
+ <attr name="accountType"/>
+ </declare-styleable>
+
+
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7215685..f655b27 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -36,6 +36,6 @@
<integer name="config_longAnimTime">300</integer>
<!-- Flag indicating whether Last Name comes before First Name.
- This becomes true in Japan, for example.-->
+ This becomes true in Japan, for example.-->
<bool name="config_lastname_comes_before_firstname">false</bool>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index b29f9ac..4af0467 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -5,16 +5,16 @@
***************************************************************
IMPORTANT NOTE FOR ANYONE MODIFYING THIS FILE
READ THIS BEFORE YOU MAKE ANY CHANGES
-
+
This file defines the binary compatibility for resources. As such,
you must be very careful when making changes here, or you will
completely break backwards compatibility with old applications.
-
+
To avoid breaking compatibility, all new resources must be placed
at the end of the list of resources of the same type. Placing a resource
in the middle of type will cause all following resources to be
assigned new resource numbers, breaking compatibility.
-
+
***************************************************************
*************************************************************** -->
<resources>
@@ -22,7 +22,7 @@
<!-- We don't want to publish private symbols in android.R as part of the
SDK. Instead, put them here. -->
<private-symbols package="com.android.internal" />
-
+
<!-- AndroidManifest.xml attributes. -->
<eat-comment />
@@ -569,10 +569,10 @@
<public type="attr" name="lineSpacingExtra" id="0x01010217" />
<public type="attr" name="lineSpacingMultiplier" id="0x01010218" />
<public type="attr" name="listChoiceIndicatorSingle" id="0x01010219" />
- <public type="attr" name="listChoiceIndicatorMultiple" id="0x0101021a" />
+ <public type="attr" name="listChoiceIndicatorMultiple" id="0x0101021a" />
<public type="attr" name="versionCode" id="0x0101021b" />
<public type="attr" name="versionName" id="0x0101021c" />
-
+
<public type="id" name="background" id="0x01020000" />
<public type="id" name="checkbox" id="0x01020001" />
<public type="id" name="content" id="0x01020002" />
@@ -601,7 +601,7 @@
<public type="id" name="button1" id="0x01020019" />
<public type="id" name="button2" id="0x0102001a" />
<public type="id" name="button3" id="0x0102001b" />
-
+
<public type="style" name="Animation" id="0x01030000" />
<public type="style" name="Animation.Activity" id="0x01030001" />
<public type="style" name="Animation.Dialog" id="0x01030002" />
@@ -748,7 +748,7 @@
<public type="drawable" name="btn_plus" id="0x01080008" />
<public type="drawable" name="btn_radio" id="0x01080009" />
<public type="drawable" name="btn_star" id="0x0108000a" />
- <public type="drawable" name="btn_star_big_off" id="0x0108000b" />
+ <public type="drawable" name="btn_star_big_off" id="0x0108000b" />
<public type="drawable" name="btn_star_big_on" id="0x0108000c" />
<public type="drawable" name="button_onoff_indicator_on" id="0x0108000d" />
<public type="drawable" name="button_onoff_indicator_off" id="0x0108000e" />
@@ -916,7 +916,7 @@
<public type="layout" name="select_dialog_item" id="0x01090011" />
<public type="layout" name="select_dialog_singlechoice" id="0x01090012" />
<public type="layout" name="select_dialog_multichoice" id="0x01090013" />
-
+
<public type="anim" name="fade_in" id="0x010a0000" />
<public type="anim" name="fade_out" id="0x010a0001" />
<public type="anim" name="slide_in_left" id="0x010a0002" />
@@ -929,9 +929,9 @@
Resources added in version 2 of the platform.
=============================================================== -->
<eat-comment />
-
+
<public type="attr" name="marqueeRepeatLimit" id="0x0101021d" />
-
+
<!-- ===============================================================
Resources added in version 3 of the platform.
=============================================================== -->
@@ -1062,7 +1062,7 @@
<public type="id" name="stopSelectingText" id="0x01020029" />
<!-- Menu ID to perform a "add to dictionary" operation. -->
<public type="id" name="addToDictionary" id="0x0102002a" />
-
+
<public type="style" name="Theme.InputMethod" id="0x01030054" />
<public type="style" name="Theme.NoDisplay" id="0x01030055" />
<public type="style" name="Animation.InputMethod" id="0x01030056" />
@@ -1070,7 +1070,7 @@
<public type="style" name="ButtonBar" id="0x01030058" />
<public type="style" name="Theme.Panel" id="0x01030059" />
<public type="style" name="Theme.Light.Panel" id="0x0103005a" />
-
+
<public type="string" name="dialog_alert_title" id="0x01040014" />
<public type="string" name="VideoView_error_text_invalid_progressive_playback" id="0x01040015" />
@@ -1081,7 +1081,7 @@
<!-- Drawable to use as a background for a taller version of the titlebar -->
<public type="drawable" name="title_bar_tall" id="0x010800a6" />
-
+
<public type="integer" name="config_shortAnimTime" id="0x010e0000" />
<public type="integer" name="config_mediumAnimTime" id="0x010e0001" />
<public type="integer" name="config_longAnimTime" id="0x010e0002" />
@@ -1131,21 +1131,31 @@
<public-padding type="array" name="donut_resource_pad" end="0x01070010" />
- <public type="drawable" name="stat_sys_vp_phone_call" />
- <public type="drawable" name="stat_sys_vp_phone_call_on_hold" />
-
- <public-padding type="drawable" name="donut_resource_pad" end="0x010800d0" />
+ <public-padding type="anim" name="donut_resource_pad" end="0x010a0020" />
- <public-padding type="layout" name="donut_resource_pad" end="0x01090020" />
+ <public-padding type="integer" name="donut_resource_pad" end="0x010e0010" />
<public type="anim" name="anticipate_interpolator" />
<public type="anim" name="overshoot_interpolator" />
<public type="anim" name="anticipate_overshoot_interpolator" />
<public type="anim" name="bounce_interpolator" />
<public type="anim" name="linear_interpolator" />
-
- <public-padding type="anim" name="donut_resource_pad" end="0x010a0020" />
- <public-padding type="integer" name="donut_resource_pad" end="0x010e0010" />
+ <public-padding type="drawable" name="donut_resource_pad" end="0x010800d0" />
+
+ <public-padding type="layout" name="donut_resource_pad" end="0x01090020" />
+
+<!-- ===============================================================
+ Resources added in Eclair.
+ =============================================================== -->
+ <eat-comment />
+
+ <public type="attr" name="accountType" />
+ <public type="attr" name="contentAuthority" />
+
+ <public type="drawable" name="stat_sys_vp_phone_call" />
+ <public type="drawable" name="stat_sys_vp_phone_call_on_hold" />
+
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e048ffe..2aed931 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -129,7 +129,7 @@
<string name="RestrictedOnNormal">Voice/SMS service is blocked.</string>
<!-- Displayed to tell the user that all voice service is blocked by access control. -->
<string name="RestrictedOnAll">All voice/SMS services are blocked.</string>
-
+
<!-- Mappings between TS 27.007 +CFCC/+CLCK "service classes" and human-readable strings--> <skip />
<!-- Example: Service was enabled for: Voice, Data -->
<string name="serviceClassVoice">Voice</string>
@@ -224,6 +224,13 @@
<!-- Displayed when a request failed because there are too many requests right now. -->
<string name="httpErrorTooManyRequests">Too many requests are being processed. Try again later.</string>
+ <!-- Account notifications --> <skip />
+ <!-- A notification is shown when the AccountManager is unable to
+ supply an auth token without prompting the user to re-enter the
+ password. This is the text that will scroll through the
+ notification bar (will be seen by the user as he uses another application). -->
+ <string name="notification_title">Sign-in error</string>
+
<!-- Sync notifications --> <skip />
<!-- A notification is shown when there is a sync error. This is the text that will scroll through the notification bar (will be seen by the user as he uses another application). -->
<string name="contentServiceSync">Sync</string>
@@ -294,7 +301,7 @@
<!-- Label for the Android system components when they are shown to the user. -->
<string name="android_system_label">Android System</string>
-
+
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgrouplab_costMoney">Services that cost you money</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
@@ -818,7 +825,7 @@
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_readFrameBuffer">read frame buffer</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_readFrameBuffer">Allows application to use
+ <string name="permdesc_readFrameBuffer">Allows application to
read the content of the frame buffer.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -1127,9 +1134,6 @@
<item>Custom</item>
</string-array>
- <!-- String which means the type "mobile phone". -->
- <string name="mobileEmailTypeName">Mobile</string>
-
<!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
<!-- Postal address types from android.provider.Contacts. This could be used when adding a new address for a contact, for example. -->
<string-array name="postalAddressTypes">
@@ -1346,7 +1350,7 @@
<!-- Title of the WebView save password dialog. If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. -->
<string name="save_password_label">Confirm</string>
-
+
<!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Text in the save password dialog, asking if the browser should remember a password. -->
<string name="save_password_message">Do you want the browser to remember this password?</string>
<!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Button in the save password dialog, saying not to remember this password. -->
@@ -1374,8 +1378,8 @@
<string name="menu_delete_shortcut_label">delete</string>
<!-- Strings used for search bar --><skip />
-
- <!-- This is the default button label in the system-wide search UI.
+
+ <!-- This is the default button label in the system-wide search UI.
It is also used by the home screen's search "widget". It should be short -->
<string name="search_go">Search</string>
@@ -1431,7 +1435,7 @@
<item quantity="one">tomorrow</item>
<item quantity="other">in <xliff:g id="count">%d</xliff:g> days</item>
</plurals>
-
+
<!-- This is used to express that something occurred some number of abbreviated seconds in the past (e.g., 5 secs ago). -->
<plurals name="abbrev_num_seconds_ago">
<item quantity="one">1 sec ago</item>
@@ -1542,7 +1546,7 @@
Example: "Mon, Dec 31, 2007 - Tue, Jan 1, 2008" -->
<string name="wday1_date1_wday2_date2">"<xliff:g id="weekday1" example="Monday">%1$s</xliff:g>, <xliff:g id="date1" example="Dec 31, 2007">%2$s</xliff:g> \u2013 <xliff:g id="weekday2" example="Thursday">%4$s</xliff:g>, <xliff:g id="date2" example="Jan 1, 2008">%5$s</xliff:g>"</string>
- <!-- Format indicating a range of time, from a time on one day to a time on another day.
+ <!-- Format indicating a range of time, from a time on one day to a time on another day.
Example: "Dec 31, 2007, 8am - Jan 1, 2008, 5pm" -->
<string name="date1_time1_date2_time2">"<xliff:g id="date1" example="Dec 31, 2007">%2$s</xliff:g>, <xliff:g id="time1" example="8am">%3$s</xliff:g> \u2013 <xliff:g id="date2" example="Jan 1, 2008">%5$s</xliff:g>, <xliff:g id="time2" example="5pm">%6$s</xliff:g>"</string>
@@ -1877,7 +1881,7 @@
<string name="usb_storage_button_mount">Mount</string>
<!-- See USB_STORAGE. This is the button text to ignore the plugging in of the phone.. -->
<string name="usb_storage_button_unmount">Don\'t mount</string>
- <!-- See USB_STORAGE_DIALOG. If there was an error mounting, this is the text. -->
+ <!-- See USB_STORAGE_DIALOG. If there was an error mounting, this is the text. -->
<string name="usb_storage_error_message">There is a problem using your SD card for USB storage.</string>
<!-- USB_STORAGE: When the user connects the phone to a computer via USB, we show a notification asking if he wants to share files across. This is the title -->
<string name="usb_storage_notification_title">USB connected</string>
@@ -1898,7 +1902,7 @@
<string name="usb_storage_stop_button_mount">Turn Off</string>
<!-- See USB_STORAGE_STOP. This is the button text to cancel stoping usb storage. -->
<string name="usb_storage_stop_button_unmount">Cancel</string>
- <!-- See USB_STORAGE_STOP_DIALOG. If there was an error stopping, this is the text. -->
+ <!-- See USB_STORAGE_STOP_DIALOG. If there was an error stopping, this is the text. -->
<string name="usb_storage_stop_error_message">We've encountered a problem turning off USB storage. Check to make sure you have unmounted the USB host, then try again.</string>
<!-- External media format dialog strings -->
@@ -1919,10 +1923,10 @@
<!-- Title of the pop-up dialog in which the user switches input method components. -->
<string name="select_input_method">Select Input Method</string>
-
+
<string name="fast_scroll_alphabet">\u0020ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
<string name="fast_scroll_numeric_alphabet">\u00200123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
-
+
<string name="candidates_style"><u>candidates</u></string>
<!-- External media notification strings -->
@@ -1969,23 +1973,23 @@
<!-- Long label for a button on a full-screen input method for the "Go" action. -->
<string name="ime_action_go">Go</string>
-
+
<!-- Long label for a button on a full-screen input method for the "Search" action. -->
<string name="ime_action_search">Search</string>
-
+
<!-- Long label for a button on a full-screen input method for the "Send" action. -->
<string name="ime_action_send">Send</string>
-
+
<!-- Long label for a button on a full-screen input method for the "Next" action. -->
<string name="ime_action_next">Next</string>
-
+
<!-- Long label for a button on a full-screen input method for the "Done" action. -->
<string name="ime_action_done">Done</string>
-
+
<!-- Long label for a button on a full-screen input method for an unknown action. -->
<string name="ime_action_default">Execute</string>
-
- <!-- Strings for search suggestions. These are going here because they are referenced by both
+
+ <!-- Strings for search suggestions. These are going here because they are referenced by both
ContactsProvider and GoogleContactsProvider -->
<skip />
@@ -1996,8 +2000,11 @@
<!-- This string appears (on two lines) when you type a number into contacts search, to let you create a contact whose phone number is the number you typed. The first line will be in bigger type than the second. -->
<string name="create_contact_using">Create contact\nusing <xliff:g id="number" example="555">%s</xliff:g></string>
- <!-- This string array should be overridden by the manufacture to present a list of carrier-id,locale pairs. This is used at startup to set a default locale by checking the system property ro.carrier for the carrier-id and searching through this array -->
- <string-array translatable="false" name="carrier_locales">
+ <!-- This string array should be overridden by the manufacture to present a list of carrier-id,locale,wifi-channel sets. This is used at startup to set system defaults by checking the system property ro.carrier for the carrier-id and searching through this array -->
+ <!-- An Array of [[Carrier-ID] -->
+ <!-- [default-locale] -->
+ <!-- [default-wifi-allowed-channels]] -->
+ <string-array translatable="false" name="carrier_properties">
</string-array>
<!-- Title for the selected state of a CompoundButton. -->
diff --git a/docs/html/guide/developing/tools/ddms.jd b/docs/html/guide/developing/tools/ddms.jd
index fa04216..f55940d 100644
--- a/docs/html/guide/developing/tools/ddms.jd
+++ b/docs/html/guide/developing/tools/ddms.jd
@@ -1,7 +1,7 @@
-page.title=Using Dalvik Debug Monitor Service (DDMS)
+page.title=Using the Dalvik Debug Monitor
@jd:body
-<p>Android ships with a debugging tool called the Dalvik Debug Monitor Service (DDMS),
+<p>Android ships with a debugging tool called the Dalvik Debug Monitor Server (DDMS),
which provides port-forwarding services, screen capture on the device, thread
and heap information on the device, logcat, process, and radio state information,
incoming call and SMS spoofing, location data spoofing, and more. This page
@@ -106,7 +106,7 @@ and some pretty cool tools.</p>
</ul>
</li>
<li> <strong>utime</strong> - cumulative time spent executing user code, in &quot;jiffies&quot; (usually
- 10ms). Only available under Linux. </li>
+ 10ms). </li>
<li> <strong>stime</strong> - cumulative time spent executing system code, in &quot;jiffies&quot; (usually
10ms). </li>
<li> <strong>Name</strong> - the name of the thread</li>
@@ -214,14 +214,15 @@ the emulator from command line, be sure to mount the sdcard again.)</p>
<h2 id="screen-capture">Screen Capture</h2>
<p>You can capture screen images on the device or emulator by selecting <strong>Device</strong>
- &gt; <strong>Screen capture...</strong> in the menu bar, or press CTRL-S.</p>
+ &gt; <strong>Screen capture...</strong> in the menu bar, or press CTRL-S.
+ Be sure to select a device first.</p>
<h2 id="exploring-processes">Exploring Processes</h2>
<p>You can see the output of <code>ps -x</code> for a specific VM by selecting <strong>Device</strong>
&gt; <strong>Show process status</strong>... in the menu bar.</p>
<h2 id="cause-a-gc-to-occur">Cause a GC to Occur</h2>
-<p>Cause garbage collection to occury by pressing the trash can button on the toolbar. </p>
+<p>Cause garbage collection to occur in the selected application by pressing the trash can button on the toolbar. </p>
<h2 id="running-dumpsys-and-dumpstate">Running Dumpsys and Dumpstate on the Device (logcat)<a name="logcat" id="logcat"></a> </h2>
<ul>
@@ -239,7 +240,7 @@ the emulator from command line, be sure to mount the sdcard again.)</p>
<h2 id="stop-a-vitrual-machine">Stop a Virtual Machine </h2>
<p>You can stop a virtual machine by selecting <strong>Actions</strong> &gt; <strong>Halt
-VM</strong>. Pressing this button causes the VM to call <code>System.exit(1)</code>.</p>
+VM</strong>. Pressing this button causes the VM to call <code>Runtime.halt(1)</code>.</p>
<h2 id="known-issues" style="color:#FF0000">Known issues with DDMS </h2>
<p>DDMS has the following known limitations:</p>
diff --git a/include/android_runtime/AndroidRuntime.h b/include/android_runtime/AndroidRuntime.h
index 78bef91..99ab2f0 100644
--- a/include/android_runtime/AndroidRuntime.h
+++ b/include/android_runtime/AndroidRuntime.h
@@ -20,7 +20,7 @@
#define _RUNTIME_ANDROID_RUNTIME_H
#include <utils/Errors.h>
-#include <utils/IBinder.h>
+#include <binder/IBinder.h>
#include <utils/String8.h>
#include <utils/String16.h>
#include <utils/Vector.h>
@@ -98,6 +98,7 @@ public:
private:
static int startReg(JNIEnv* env);
+ int startVm(JavaVM** pJavaVM, JNIEnv** pEnv);
Vector<JavaVMOption> mOptions;
diff --git a/include/utils/Binder.h b/include/binder/Binder.h
index b5b8d98..47b2bb9 100644
--- a/include/utils/Binder.h
+++ b/include/binder/Binder.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_BINDER_H
#define ANDROID_BINDER_H
-#include <utils/IBinder.h>
+#include <binder/IBinder.h>
// ---------------------------------------------------------------------------
namespace android {
@@ -27,7 +27,7 @@ class BBinder : public IBinder
public:
BBinder();
- virtual String16 getInterfaceDescriptor() const;
+ virtual const String16& getInterfaceDescriptor() const;
virtual bool isBinderAlive() const;
virtual status_t pingBinder();
virtual status_t dump(int fd, const Vector<String16>& args);
@@ -71,6 +71,7 @@ private:
Extras* mExtras;
void* mReserved0;
+ static String16 sEmptyDescriptor;
};
// ---------------------------------------------------------------------------
diff --git a/include/utils/BpBinder.h b/include/binder/BpBinder.h
index 7b96e29..7ef93aa 100644
--- a/include/utils/BpBinder.h
+++ b/include/binder/BpBinder.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_BPBINDER_H
#define ANDROID_BPBINDER_H
-#include <utils/IBinder.h>
+#include <binder/IBinder.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
@@ -31,7 +31,7 @@ public:
inline int32_t handle() const { return mHandle; }
- virtual String16 getInterfaceDescriptor() const;
+ virtual const String16& getInterfaceDescriptor() const;
virtual bool isBinderAlive() const;
virtual status_t pingBinder();
virtual status_t dump(int fd, const Vector<String16>& args);
@@ -106,6 +106,7 @@ private:
};
void reportOneDeath(const Obituary& obit);
+ bool isDescriptorCached() const;
mutable Mutex mLock;
volatile int32_t mAlive;
@@ -113,6 +114,7 @@ private:
Vector<Obituary>* mObituaries;
ObjectManager mObjects;
Parcel* mConstantData;
+ mutable String16 mDescriptorCache;
};
}; // namespace android
diff --git a/include/utils/IBinder.h b/include/binder/IBinder.h
index 7370330..884b5c1 100644
--- a/include/utils/IBinder.h
+++ b/include/binder/IBinder.h
@@ -56,7 +56,7 @@ public:
FLAG_ONEWAY = 0x00000001
};
- inline IBinder() { }
+ IBinder();
/**
* Check if this IBinder implements the interface named by
@@ -69,7 +69,7 @@ public:
* Return the canonical name of the interface provided by this IBinder
* object.
*/
- virtual String16 getInterfaceDescriptor() const = 0;
+ virtual const String16& getInterfaceDescriptor() const = 0;
virtual bool isBinderAlive() const = 0;
virtual status_t pingBinder() = 0;
@@ -147,7 +147,7 @@ public:
virtual BpBinder* remoteBinder();
protected:
- inline virtual ~IBinder() { }
+ virtual ~IBinder();
private:
};
diff --git a/include/utils/IInterface.h b/include/binder/IInterface.h
index 959722a..273d922 100644
--- a/include/utils/IInterface.h
+++ b/include/binder/IInterface.h
@@ -18,7 +18,7 @@
#ifndef ANDROID_IINTERFACE_H
#define ANDROID_IINTERFACE_H
-#include <utils/Binder.h>
+#include <binder/Binder.h>
namespace android {
@@ -27,10 +27,12 @@ namespace android {
class IInterface : public virtual RefBase
{
public:
+ IInterface();
sp<IBinder> asBinder();
sp<const IBinder> asBinder() const;
-
+
protected:
+ virtual ~IInterface();
virtual IBinder* onAsBinder() = 0;
};
@@ -49,7 +51,7 @@ class BnInterface : public INTERFACE, public BBinder
{
public:
virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
- virtual String16 getInterfaceDescriptor() const;
+ virtual const String16& getInterfaceDescriptor() const;
protected:
virtual IBinder* onAsBinder();
@@ -72,11 +74,14 @@ protected:
#define DECLARE_META_INTERFACE(INTERFACE) \
static const String16 descriptor; \
static sp<I##INTERFACE> asInterface(const sp<IBinder>& obj); \
- virtual String16 getInterfaceDescriptor() const; \
+ virtual const String16& getInterfaceDescriptor() const; \
+ I##INTERFACE(); \
+ virtual ~I##INTERFACE(); \
+
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
const String16 I##INTERFACE::descriptor(NAME); \
- String16 I##INTERFACE::getInterfaceDescriptor() const { \
+ const String16& I##INTERFACE::getInterfaceDescriptor() const { \
return I##INTERFACE::descriptor; \
} \
sp<I##INTERFACE> I##INTERFACE::asInterface(const sp<IBinder>& obj) \
@@ -92,9 +97,16 @@ protected:
} \
return intr; \
} \
+ I##INTERFACE::I##INTERFACE() { } \
+ I##INTERFACE::~I##INTERFACE() { } \
+
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ if (!data.checkInterface(this)) { return PERMISSION_DENIED; } \
+
// ----------------------------------------------------------------------
-// No user-servicable parts after this...
+// No user-serviceable parts after this...
template<typename INTERFACE>
inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
@@ -105,7 +117,7 @@ inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
}
template<typename INTERFACE>
-inline String16 BnInterface<INTERFACE>::getInterfaceDescriptor() const
+inline const String16& BnInterface<INTERFACE>::getInterfaceDescriptor() const
{
return INTERFACE::getInterfaceDescriptor();
}
diff --git a/include/utils/IMemory.h b/include/binder/IMemory.h
index 35a3fd7..ae042cb 100644
--- a/include/utils/IMemory.h
+++ b/include/binder/IMemory.h
@@ -23,7 +23,7 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
namespace android {
@@ -59,6 +59,10 @@ public:
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
+
+ BnMemoryHeap();
+protected:
+ virtual ~BnMemoryHeap();
};
// ----------------------------------------------------------------------------
@@ -85,6 +89,10 @@ public:
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
+
+ BnMemory();
+protected:
+ virtual ~BnMemory();
};
// ----------------------------------------------------------------------------
diff --git a/include/utils/IPCThreadState.h b/include/binder/IPCThreadState.h
index 0490fd3..78306b2 100644
--- a/include/utils/IPCThreadState.h
+++ b/include/binder/IPCThreadState.h
@@ -18,8 +18,8 @@
#define ANDROID_IPC_THREAD_STATE_H
#include <utils/Errors.h>
-#include <utils/Parcel.h>
-#include <utils/ProcessState.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
#include <utils/Vector.h>
#ifdef HAVE_WIN32_PROC
diff --git a/include/utils/IPermissionController.h b/include/binder/IPermissionController.h
index cb1dd34..f9d371b 100644
--- a/include/utils/IPermissionController.h
+++ b/include/binder/IPermissionController.h
@@ -18,7 +18,7 @@
#ifndef ANDROID_IPERMISSION_CONTROLLER_H
#define ANDROID_IPERMISSION_CONTROLLER_H
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
namespace android {
diff --git a/include/utils/IServiceManager.h b/include/binder/IServiceManager.h
index e3d99fe..ea149dd 100644
--- a/include/utils/IServiceManager.h
+++ b/include/binder/IServiceManager.h
@@ -18,8 +18,8 @@
#ifndef ANDROID_ISERVICE_MANAGER_H
#define ANDROID_ISERVICE_MANAGER_H
-#include <utils/IInterface.h>
-#include <utils/IPermissionController.h>
+#include <binder/IInterface.h>
+#include <binder/IPermissionController.h>
#include <utils/Vector.h>
#include <utils/String16.h>
diff --git a/include/utils/MemoryBase.h b/include/binder/MemoryBase.h
index eb5a9d2..463e26d 100644
--- a/include/utils/MemoryBase.h
+++ b/include/binder/MemoryBase.h
@@ -20,7 +20,7 @@
#include <stdlib.h>
#include <stdint.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
namespace android {
diff --git a/include/utils/MemoryDealer.h b/include/binder/MemoryDealer.h
index 454b627..d057556 100644
--- a/include/utils/MemoryDealer.h
+++ b/include/binder/MemoryDealer.h
@@ -21,9 +21,9 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <utils/threads.h>
-#include <utils/MemoryHeapBase.h>
+#include <binder/MemoryHeapBase.h>
namespace android {
// ----------------------------------------------------------------------------
@@ -39,6 +39,10 @@ class HeapInterface : public virtual BnMemoryHeap
public:
// all values must be page-aligned
virtual sp<IMemory> mapMemory(size_t offset, size_t size) = 0;
+
+ HeapInterface();
+protected:
+ virtual ~HeapInterface();
};
// ----------------------------------------------------------------------------
@@ -61,6 +65,10 @@ public:
virtual void dump(const char* what, uint32_t flags = 0) const = 0;
virtual void dump(String8& res,
const char* what, uint32_t flags = 0) const = 0;
+
+ AllocatorInterface();
+protected:
+ virtual ~AllocatorInterface();
};
// ----------------------------------------------------------------------------
@@ -71,6 +79,7 @@ public:
class SharedHeap : public HeapInterface, public MemoryHeapBase
{
public:
+ SharedHeap();
SharedHeap(size_t size, uint32_t flags = 0, char const * name = NULL);
virtual ~SharedHeap();
virtual sp<IMemory> mapMemory(size_t offset, size_t size);
diff --git a/include/utils/MemoryHeapBase.h b/include/binder/MemoryHeapBase.h
index 574acf4..83c7283 100644
--- a/include/utils/MemoryHeapBase.h
+++ b/include/binder/MemoryHeapBase.h
@@ -20,7 +20,7 @@
#include <stdlib.h>
#include <stdint.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
namespace android {
diff --git a/include/utils/MemoryHeapPmem.h b/include/binder/MemoryHeapPmem.h
index 60335ad..dbf26ff 100644
--- a/include/utils/MemoryHeapPmem.h
+++ b/include/binder/MemoryHeapPmem.h
@@ -20,9 +20,9 @@
#include <stdlib.h>
#include <stdint.h>
-#include <utils/MemoryDealer.h>
-#include <utils/MemoryHeapBase.h>
-#include <utils/IMemory.h>
+#include <binder/MemoryDealer.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/IMemory.h>
#include <utils/SortedVector.h>
namespace android {
diff --git a/include/utils/Parcel.h b/include/binder/Parcel.h
index af1490a..58c2d9a 100644
--- a/include/utils/Parcel.h
+++ b/include/binder/Parcel.h
@@ -57,7 +57,8 @@ public:
status_t writeInterfaceToken(const String16& interface);
bool enforceInterface(const String16& interface) const;
-
+ bool checkInterface(IBinder*) const;
+
void freeData();
const size_t* objects() const;
@@ -147,7 +148,7 @@ public:
release_func relFunc, void* relCookie);
void print(TextOutput& to, uint32_t flags = 0) const;
-
+
private:
Parcel(const Parcel& o);
Parcel& operator=(const Parcel& o);
diff --git a/include/utils/ProcessState.h b/include/binder/ProcessState.h
index 39584f4..feeb3c3 100644
--- a/include/utils/ProcessState.h
+++ b/include/binder/ProcessState.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_PROCESS_STATE_H
#define ANDROID_PROCESS_STATE_H
-#include <utils/IBinder.h>
+#include <binder/IBinder.h>
#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <utils/String16.h>
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 3694803..106807e 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -26,8 +26,8 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
-#include <utils/IMemory.h>
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
#include <utils/threads.h>
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index ba0467c..0955819 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -26,8 +26,8 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
-#include <utils/IMemory.h>
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
#include <utils/threads.h>
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 3e59d85..bac3d29 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -23,7 +23,7 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
#include <media/IAudioTrack.h>
#include <media/IAudioRecord.h>
#include <media/IAudioFlingerClient.h>
diff --git a/include/media/IAudioFlingerClient.h b/include/media/IAudioFlingerClient.h
index c3deb0b..383ec0c 100644
--- a/include/media/IAudioFlingerClient.h
+++ b/include/media/IAudioFlingerClient.h
@@ -19,7 +19,7 @@
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
namespace android {
diff --git a/include/media/IAudioRecord.h b/include/media/IAudioRecord.h
index 9d45d2d..46735de 100644
--- a/include/media/IAudioRecord.h
+++ b/include/media/IAudioRecord.h
@@ -22,8 +22,8 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
-#include <utils/IMemory.h>
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
namespace android {
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
index 12f2111..de6426a 100644
--- a/include/media/IAudioTrack.h
+++ b/include/media/IAudioTrack.h
@@ -22,8 +22,8 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
-#include <utils/IMemory.h>
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
namespace android {
diff --git a/include/media/IMediaMetadataRetriever.h b/include/media/IMediaMetadataRetriever.h
index c677e83..9baba8e 100644
--- a/include/media/IMediaMetadataRetriever.h
+++ b/include/media/IMediaMetadataRetriever.h
@@ -19,9 +19,9 @@
#define ANDROID_IMEDIAMETADATARETRIEVER_H
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
namespace android {
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index a683e74..2c4bc2a 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -18,8 +18,8 @@
#define ANDROID_IMEDIAPLAYER_H
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
namespace android {
diff --git a/include/media/IMediaPlayerClient.h b/include/media/IMediaPlayerClient.h
index 5d32811..eee6c97 100644
--- a/include/media/IMediaPlayerClient.h
+++ b/include/media/IMediaPlayerClient.h
@@ -18,8 +18,8 @@
#define ANDROID_IMEDIAPLAYERCLIENT_H
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
namespace android {
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index 8125cc9..469098c 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -18,8 +18,8 @@
#define ANDROID_IMEDIAPLAYERSERVICE_H
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
#include <media/IMediaPlayerClient.h>
#include <media/IMediaPlayer.h>
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
index 64d3a40..24ac82b 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -18,7 +18,7 @@
#ifndef ANDROID_IMEDIARECORDER_H
#define ANDROID_IMEDIARECORDER_H
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
namespace android {
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index f2719d3..3db8a0f 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -20,7 +20,7 @@
#include <utils/Errors.h> // for status_t
#include <utils/threads.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <media/IMediaMetadataRetriever.h>
namespace android {
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 255a67b..704a8cb 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_MEDIAPLAYER_H
#define ANDROID_MEDIAPLAYER_H
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <ui/Surface.h>
#include <media/IMediaPlayerClient.h>
#include <media/IMediaPlayer.h>
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index aebe191..7555521 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -18,7 +18,10 @@
#ifndef ANDROID_MEDIARECORDER_H
#define ANDROID_MEDIARECORDER_H
-#include <utils.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <media/IMediaPlayerClient.h>
namespace android {
diff --git a/include/media/mediascanner.h b/include/media/mediascanner.h
index fbef1db..7749566 100644
--- a/include/media/mediascanner.h
+++ b/include/media/mediascanner.h
@@ -17,7 +17,10 @@
#ifndef MEDIASCANNER_H
#define MEDIASCANNER_H
-#include <utils.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <pthread.h>
namespace android {
diff --git a/libs/utils/executablepath_darwin.cpp b/include/private/binder/Static.h
index 2e3c3a0..5b0f9fc 100644
--- a/libs/utils/executablepath_darwin.cpp
+++ b/include/private/binder/Static.h
@@ -14,18 +14,26 @@
* limitations under the License.
*/
-#include <utils/executablepath.h>
-#import <Carbon/Carbon.h>
-#include <unistd.h>
+// All static variables go here, to control initialization and
+// destruction order in the library.
-void executablepath(char s[PATH_MAX])
-{
- ProcessSerialNumber psn;
- GetCurrentProcess(&psn);
- CFDictionaryRef dict;
- dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
- CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict,
- CFSTR("CFBundleExecutable"));
- CFStringGetCString(value, s, PATH_MAX+1, kCFStringEncodingUTF8);
-}
+#include <utils/threads.h>
+#include <binder/IBinder.h>
+#include <binder/IMemory.h>
+#include <binder/ProcessState.h>
+#include <binder/IPermissionController.h>
+#include <binder/IServiceManager.h>
+
+namespace android {
+
+// For ProcessState.cpp
+extern Mutex gProcessMutex;
+extern sp<ProcessState> gProcess;
+
+// For ServiceManager.cpp
+extern Mutex gDefaultServiceManagerLock;
+extern sp<IServiceManager> gDefaultServiceManager;
+extern sp<IPermissionController> gPermissionController;
+
+} // namespace android
diff --git a/include/private/utils/binder_module.h b/include/private/binder/binder_module.h
index fdf327e..fdf327e 100644
--- a/include/private/utils/binder_module.h
+++ b/include/private/binder/binder_module.h
diff --git a/include/private/utils/Static.h b/include/private/utils/Static.h
index f1439b7..d95ae0d 100644
--- a/include/private/utils/Static.h
+++ b/include/private/utils/Static.h
@@ -20,14 +20,6 @@
#include <utils/threads.h>
#include <utils/KeyedVector.h>
-#ifndef LIBUTILS_NATIVE
-#include <utils/IBinder.h>
-#include <utils/IMemory.h>
-#include <utils/ProcessState.h>
-#include <utils/IPermissionController.h>
-#include <utils/IServiceManager.h>
-#endif
-
namespace android {
// For TextStream.cpp
extern Vector<int32_t> gTextBuffers;
@@ -40,19 +32,4 @@ extern void terminate_string8();
extern void initialize_string16();
extern void terminate_string16();
-
-
-#ifndef LIBUTILS_NATIVE
-
-// For ProcessState.cpp
-extern Mutex gProcessMutex;
-extern sp<ProcessState> gProcess;
-
-// For ServiceManager.cpp
-extern Mutex gDefaultServiceManagerLock;
-extern sp<IServiceManager> gDefaultServiceManager;
-extern sp<IPermissionController> gPermissionController;
-
-#endif
-
} // namespace android
diff --git a/include/ui/CameraHardwareInterface.h b/include/ui/CameraHardwareInterface.h
index 73036f0..2cdcc06 100644
--- a/include/ui/CameraHardwareInterface.h
+++ b/include/ui/CameraHardwareInterface.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
#define ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <utils/RefBase.h>
#include <ui/CameraParameters.h>
#include <ui/Overlay.h>
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
index 3848d8c..e12c4f1 100644
--- a/include/ui/EventHub.h
+++ b/include/ui/EventHub.h
@@ -20,7 +20,10 @@
#include <utils/String8.h>
#include <utils/threads.h>
-#include <utils.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <linux/input.h>
diff --git a/include/ui/ICamera.h b/include/ui/ICamera.h
index 241fb63..1df7914 100644
--- a/include/ui/ICamera.h
+++ b/include/ui/ICamera.h
@@ -18,10 +18,10 @@
#define ANDROID_HARDWARE_ICAMERA_H
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
#include <ui/ISurface.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <utils/String8.h>
#include <ui/Camera.h>
diff --git a/include/ui/ICameraClient.h b/include/ui/ICameraClient.h
index c4bdd07..f38a6aa 100644
--- a/include/ui/ICameraClient.h
+++ b/include/ui/ICameraClient.h
@@ -18,9 +18,9 @@
#define ANDROID_HARDWARE_ICAMERA_APP_H
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
namespace android {
diff --git a/include/ui/ICameraService.h b/include/ui/ICameraService.h
index c652c51..061681a 100644
--- a/include/ui/ICameraService.h
+++ b/include/ui/ICameraService.h
@@ -18,8 +18,8 @@
#define ANDROID_HARDWARE_ICAMERASERVICE_H
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
#include <ui/ICameraClient.h>
#include <ui/ICamera.h>
diff --git a/include/ui/IOverlay.h b/include/ui/IOverlay.h
index 699b1b0..af3add1 100644
--- a/include/ui/IOverlay.h
+++ b/include/ui/IOverlay.h
@@ -21,7 +21,7 @@
#include <sys/types.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
#include <utils/RefBase.h>
#include <ui/PixelFormat.h>
diff --git a/include/ui/ISurface.h b/include/ui/ISurface.h
index 87b320f..136e801 100644
--- a/include/ui/ISurface.h
+++ b/include/ui/ISurface.h
@@ -21,7 +21,7 @@
#include <sys/types.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
#include <utils/RefBase.h>
#include <ui/PixelFormat.h>
diff --git a/include/ui/ISurfaceComposer.h b/include/ui/ISurfaceComposer.h
index 5c64b22..5b062a8 100644
--- a/include/ui/ISurfaceComposer.h
+++ b/include/ui/ISurfaceComposer.h
@@ -22,7 +22,7 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
#include <ui/PixelFormat.h>
#include <ui/ISurfaceFlingerClient.h>
diff --git a/include/ui/ISurfaceFlingerClient.h b/include/ui/ISurfaceFlingerClient.h
index 5b9361d..b6cbb0b 100644
--- a/include/ui/ISurfaceFlingerClient.h
+++ b/include/ui/ISurfaceFlingerClient.h
@@ -21,7 +21,7 @@
#include <sys/types.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
#include <utils/RefBase.h>
#include <ui/ISurface.h>
diff --git a/include/ui/Overlay.h b/include/ui/Overlay.h
index 66514b4..9ba2f7b 100644
--- a/include/ui/Overlay.h
+++ b/include/ui/Overlay.h
@@ -21,7 +21,7 @@
#include <sys/types.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
diff --git a/include/ui/Region.h b/include/ui/Region.h
index 7689673..68cb52e 100644
--- a/include/ui/Region.h
+++ b/include/ui/Region.h
@@ -21,7 +21,7 @@
#include <sys/types.h>
#include <utils/Vector.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <ui/Rect.h>
diff --git a/include/utils/LogSocket.h b/include/utils/LogSocket.h
deleted file mode 100644
index 01fbfb5..0000000
--- a/include/utils/LogSocket.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* utils/LogSocket.h
-**
-** Copyright 2008, The Android Open Source Project
-**
-** This file is dual licensed. It may be redistributed and/or modified
-** under the terms of the Apache 2.0 License OR version 2 of the GNU
-** General Public License.
-*/
-
-#ifndef _UTILS_LOGSOCKET_H
-#define _UTILS_LOGSOCKET_H
-
-#define SOCKET_CLOSE_LOCAL 0
-
-void add_send_stats(int fd, int send);
-void add_recv_stats(int fd, int recv);
-void log_socket_close(int fd, short reason);
-void log_socket_connect(int fd, unsigned int ip, unsigned short port);
-
-#endif /* _UTILS_LOGSOCKET_H */
diff --git a/include/utils/Pipe.h b/include/utils/Pipe.h
deleted file mode 100644
index 6404168..0000000
--- a/include/utils/Pipe.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// FIFO I/O.
-//
-#ifndef _LIBS_UTILS_PIPE_H
-#define _LIBS_UTILS_PIPE_H
-
-#ifdef HAVE_ANDROID_OS
-#error DO NOT USE THIS FILE IN THE DEVICE BUILD
-#endif
-
-namespace android {
-
-/*
- * Simple anonymous unidirectional pipe.
- *
- * The primary goal is to create an implementation with minimal overhead
- * under Linux. Making Windows, Mac OS X, and Linux all work the same way
- * is a secondary goal. Part of this goal is to have something that can
- * be fed to a select() call, so that the application can sleep in the
- * kernel until something interesting happens.
- */
-class Pipe {
-public:
- Pipe(void);
- virtual ~Pipe(void);
-
- /* Create the pipe */
- bool create(void);
-
- /* Create a read-only pipe, using the supplied handle as read handle */
- bool createReader(unsigned long handle);
- /* Create a write-only pipe, using the supplied handle as write handle */
- bool createWriter(unsigned long handle);
-
- /* Is this object ready to go? */
- bool isCreated(void);
-
- /*
- * Read "count" bytes from the pipe. Returns the amount of data read,
- * or 0 if no data available and we're non-blocking.
- * Returns -1 on error.
- */
- int read(void* buf, int count);
-
- /*
- * Write "count" bytes into the pipe. Returns number of bytes written,
- * or 0 if there's no room for more data and we're non-blocking.
- * Returns -1 on error.
- */
- int write(const void* buf, int count);
-
- /* Returns "true" if data is available to read */
- bool readReady(void);
-
- /* Enable or disable non-blocking I/O for reads */
- bool setReadNonBlocking(bool val);
- /* Enable or disable non-blocking I/O for writes. Only works on Linux. */
- bool setWriteNonBlocking(bool val);
-
- /*
- * Get the handle. Only useful in some platform-specific situations.
- */
- unsigned long getReadHandle(void);
- unsigned long getWriteHandle(void);
-
- /*
- * Modify inheritance, i.e. whether or not a child process will get
- * copies of the descriptors. Systems with fork+exec allow us to close
- * the descriptors before launching the child process, but Win32
- * doesn't allow it.
- */
- bool disallowReadInherit(void);
- bool disallowWriteInherit(void);
-
- /*
- * Close one side or the other. Useful in the parent after launching
- * a child process.
- */
- bool closeRead(void);
- bool closeWrite(void);
-
-private:
- bool mReadNonBlocking;
- bool mWriteNonBlocking;
-
- unsigned long mReadHandle;
- unsigned long mWriteHandle;
-};
-
-}; // android
-
-#endif // _LIBS_UTILS_PIPE_H
diff --git a/include/utils/Socket.h b/include/utils/Socket.h
deleted file mode 100644
index 8b7f406..0000000
--- a/include/utils/Socket.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Socket class. Modeled after Java classes.
-//
-#ifndef _RUNTIME_SOCKET_H
-#define _RUNTIME_SOCKET_H
-
-#include <utils/inet_address.h>
-#include <sys/types.h>
-
-namespace android {
-
-/*
- * Basic socket class, needed to abstract away the differences between
- * BSD sockets and WinSock. This establishes a streaming network
- * connection (TCP/IP) to somebody.
- */
-class Socket {
-public:
- Socket(void);
- ~Socket(void);
-
- // Create a connection to somewhere.
- // Return 0 on success.
- int connect(const char* host, int port);
- int connect(const InetAddress* addr, int port);
-
-
- // Close the socket. Don't try to use this object again after
- // calling this. Returns false on failure.
- bool close(void);
-
- // If we created the socket without an address, we can use these
- // to finish the connection. Returns 0 on success.
- int bind(const SocketAddress& bindPoint);
- int connect(const SocketAddress& endPoint);
-
- // Here we deviate from the traditional object-oriented fanciness
- // and just provide read/write operators instead of getters for
- // objects that abstract a stream.
- //
- // Standard read/write semantics.
- int read(void* buf, ssize_t len) const;
- int write(const void* buf, ssize_t len) const;
-
- // This must be called once, at program startup.
- static bool bootInit(void);
- static void finalShutdown(void);
-
-private:
- // Internal function that establishes a connection.
- int doConnect(const InetSocketAddress& addr);
-
- unsigned long mSock; // holds SOCKET or int
-
- static bool mBootInitialized;
-};
-
-
-// debug -- unit tests
-void TestSockets(void);
-
-}; // namespace android
-
-#endif // _RUNTIME_SOCKET_H
diff --git a/include/utils/StringArray.h b/include/utils/StringArray.h
new file mode 100644
index 0000000..c244587
--- /dev/null
+++ b/include/utils/StringArray.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+//
+// Sortable array of strings. STL-ish, but STL-free.
+//
+#ifndef _LIBS_UTILS_STRING_ARRAY_H
+#define _LIBS_UTILS_STRING_ARRAY_H
+
+#include <stdlib.h>
+#include <string.h>
+
+namespace android {
+
+//
+// An expanding array of strings. Add, get, sort, delete.
+//
+class StringArray {
+public:
+ StringArray();
+ virtual ~StringArray();
+
+ //
+ // Add a string. A copy of the string is made.
+ //
+ bool push_back(const char* str);
+
+ //
+ // Delete an entry.
+ //
+ void erase(int idx);
+
+ //
+ // Sort the array.
+ //
+ void sort(int (*compare)(const void*, const void*));
+
+ //
+ // Pass this to the sort routine to do an ascending alphabetical sort.
+ //
+ static int cmpAscendingAlpha(const void* pstr1, const void* pstr2);
+
+ //
+ // Get the #of items in the array.
+ //
+ inline int size(void) const { return mCurrent; }
+
+ //
+ // Return entry N.
+ // [should use operator[] here]
+ //
+ const char* getEntry(int idx) const {
+ return (unsigned(idx) >= unsigned(mCurrent)) ? NULL : mArray[idx];
+ }
+
+ //
+ // Set entry N to specified string.
+ // [should use operator[] here]
+ //
+ void setEntry(int idx, const char* str);
+
+private:
+ int mMax;
+ int mCurrent;
+ char** mArray;
+};
+
+}; // namespace android
+
+#endif // _LIBS_UTILS_STRING_ARRAY_H
diff --git a/include/utils/TextOutput.h b/include/utils/TextOutput.h
index d8d86ba..de2fbbe 100644
--- a/include/utils/TextOutput.h
+++ b/include/utils/TextOutput.h
@@ -28,8 +28,8 @@ namespace android {
class TextOutput
{
public:
- TextOutput() { }
- virtual ~TextOutput() { }
+ TextOutput();
+ virtual ~TextOutput();
virtual status_t print(const char* txt, size_t len) = 0;
virtual void moveIndent(int delta) = 0;
diff --git a/include/utils/TimerProbe.h b/include/utils/TimerProbe.h
deleted file mode 100644
index f2e32b2..0000000
--- a/include/utils/TimerProbe.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_TIMER_PROBE_H
-#define ANDROID_TIMER_PROBE_H
-
-#if 0 && defined(HAVE_POSIX_CLOCKS)
-#define ENABLE_TIMER_PROBE 1
-#else
-#define ENABLE_TIMER_PROBE 0
-#endif
-
-#if ENABLE_TIMER_PROBE
-
-#include <time.h>
-#include <sys/time.h>
-#include <utils/Vector.h>
-
-#define TIMER_PROBE(tag) \
- static int _timer_slot_; \
- android::TimerProbe probe(tag, &_timer_slot_)
-#define TIMER_PROBE_END() probe.end()
-#else
-#define TIMER_PROBE(tag)
-#define TIMER_PROBE_END()
-#endif
-
-#if ENABLE_TIMER_PROBE
-namespace android {
-
-class TimerProbe {
-public:
- TimerProbe(const char tag[], int* slot);
- void end();
- ~TimerProbe();
-private:
- struct Bucket {
- int mStart, mReal, mProcess, mThread, mCount;
- const char* mTag;
- int* mSlotPtr;
- int mIndent;
- };
- static Vector<Bucket> gBuckets;
- static TimerProbe* gExecuteChain;
- static int gIndent;
- static timespec gRealBase;
- TimerProbe* mNext;
- static uint32_t ElapsedTime(const timespec& start, const timespec& end);
- void print(const timespec& r, const timespec& p, const timespec& t) const;
- timespec mRealStart, mPStart, mTStart;
- const char* mTag;
- int mIndent;
- int mBucket;
-};
-
-}; // namespace android
-
-#endif
-#endif
diff --git a/include/utils/Timers.h b/include/utils/Timers.h
index 9610399..9a9e07c 100644
--- a/include/utils/Timers.h
+++ b/include/utils/Timers.h
@@ -88,9 +88,6 @@ nsecs_t systemTime(int clock = SYSTEM_TIME_MONOTONIC);
nsecs_t systemTime(int clock);
#endif // def __cplusplus
-// return the system-time according to the specified clock
-int sleepForInterval(long interval, struct timeval* pNextTick);
-
#ifdef __cplusplus
} // extern "C"
#endif
@@ -108,15 +105,15 @@ namespace android {
*/
class DurationTimer {
public:
- DurationTimer(void) {}
- ~DurationTimer(void) {}
+ DurationTimer() {}
+ ~DurationTimer() {}
// Start the timer.
- void start(void);
+ void start();
// Stop the timer.
- void stop(void);
+ void stop();
// Get the duration in microseconds.
- long long durationUsecs(void) const;
+ long long durationUsecs() const;
// Subtract two timevals. Returns the difference (ptv1-ptv2) in
// microseconds.
diff --git a/include/utils/inet_address.h b/include/utils/inet_address.h
deleted file mode 100644
index dbd8672..0000000
--- a/include/utils/inet_address.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Internet address classes. Modeled after Java classes.
-//
-#ifndef _RUNTIME_INET_ADDRESS_H
-#define _RUNTIME_INET_ADDRESS_H
-
-#ifdef HAVE_ANDROID_OS
-#error DO NOT USE THIS FILE IN THE DEVICE BUILD
-#endif
-
-
-namespace android {
-
-/*
- * This class holds Internet addresses. Perhaps more useful is its
- * ability to look up addresses by name.
- *
- * Invoke one of the static factory methods to create a new object.
- */
-class InetAddress {
-public:
- virtual ~InetAddress(void);
-
- // create from w.x.y.z or foo.bar.com notation
- static InetAddress* getByName(const char* host);
-
- // copy-construction
- InetAddress(const InetAddress& orig);
-
- const void* getAddress(void) const { return mAddress; }
- int getAddressLength(void) const { return mLength; }
- const char* getHostName(void) const { return mName; }
-
-private:
- InetAddress(void);
- // assignment (private)
- InetAddress& operator=(const InetAddress& addr);
-
- // use a void* here so we don't have to expose actual socket headers
- void* mAddress; // this is really a ptr to sockaddr_in
- int mLength;
- char* mName;
-};
-
-
-/*
- * Base class for socket addresses.
- */
-class SocketAddress {
-public:
- SocketAddress() {}
- virtual ~SocketAddress() {}
-};
-
-
-/*
- * Internet address class. This combines an InetAddress with a port.
- */
-class InetSocketAddress : public SocketAddress {
-public:
- InetSocketAddress() :
- mAddress(0), mPort(-1)
- {}
- ~InetSocketAddress(void) {
- delete mAddress;
- }
-
- // Create an address with a host wildcard (useful for servers).
- bool create(int port);
- // Create an address with the specified host and port.
- bool create(const InetAddress* addr, int port);
- // Create an address with the specified host and port. Does the
- // hostname lookup.
- bool create(const char* host, int port);
-
- const InetAddress* getAddress(void) const { return mAddress; }
- const int getPort(void) const { return mPort; }
- const char* getHostName(void) const { return mAddress->getHostName(); }
-
-private:
- InetAddress* mAddress;
- int mPort;
-};
-
-}; // namespace android
-
-#endif // _RUNTIME_INET_ADDRESS_H
diff --git a/include/utils/misc.h b/include/utils/misc.h
index 62e84b4..23f2a4c 100644
--- a/include/utils/misc.h
+++ b/include/utils/misc.h
@@ -21,7 +21,7 @@
#define _LIBS_UTILS_MISC_H
#include <sys/time.h>
-#include "utils/Endian.h"
+#include <utils/Endian.h>
namespace android {
diff --git a/include/utils/ported.h b/include/utils/ported.h
deleted file mode 100644
index eb3be01..0000000
--- a/include/utils/ported.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Standard functions ported to the current platform. Note these are NOT
-// in the "android" namespace.
-//
-#ifndef _LIBS_UTILS_PORTED_H
-#define _LIBS_UTILS_PORTED_H
-
-#include <sys/time.h> // for timeval
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* library replacement functions */
-#if defined(NEED_GETTIMEOFDAY)
-int gettimeofday(struct timeval* tv, struct timezone* tz);
-#endif
-#if defined(NEED_USLEEP)
-void usleep(unsigned long usec);
-#endif
-#if defined(NEED_PIPE)
-int pipe(int filedes[2]);
-#endif
-#if defined(NEED_SETENV)
-int setenv(const char* name, const char* value, int overwrite);
-void unsetenv(const char* name);
-char* getenv(const char* name);
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _LIBS_UTILS_PORTED_H
diff --git a/include/utils/string_array.h b/include/utils/string_array.h
deleted file mode 100644
index 064dda2..0000000
--- a/include/utils/string_array.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Sortable array of strings. STL-ish, but STL-free.
-//
-#ifndef _LIBS_UTILS_STRING_ARRAY_H
-#define _LIBS_UTILS_STRING_ARRAY_H
-
-#include <stdlib.h>
-#include <string.h>
-
-namespace android {
-
-//
-// An expanding array of strings. Add, get, sort, delete.
-//
-class StringArray {
-public:
- StringArray()
- : mMax(0), mCurrent(0), mArray(NULL)
- {}
- virtual ~StringArray() {
- for (int i = 0; i < mCurrent; i++)
- delete[] mArray[i];
- delete[] mArray;
- }
-
- //
- // Add a string. A copy of the string is made.
- //
- bool push_back(const char* str) {
- if (mCurrent >= mMax) {
- char** tmp;
-
- if (mMax == 0)
- mMax = 16; // initial storage
- else
- mMax *= 2;
-
- tmp = new char*[mMax];
- if (tmp == NULL)
- return false;
-
- memcpy(tmp, mArray, mCurrent * sizeof(char*));
- delete[] mArray;
- mArray = tmp;
- }
-
- int len = strlen(str);
- mArray[mCurrent] = new char[len+1];
- memcpy(mArray[mCurrent], str, len+1);
- mCurrent++;
-
- return true;
- }
-
- //
- // Delete an entry.
- //
- void erase(int idx) {
- if (idx < 0 || idx >= mCurrent)
- return;
- delete[] mArray[idx];
- if (idx < mCurrent-1) {
- memmove(&mArray[idx], &mArray[idx+1],
- (mCurrent-1 - idx) * sizeof(char*));
- }
- mCurrent--;
- }
-
- //
- // Sort the array.
- //
- void sort(int (*compare)(const void*, const void*)) {
- qsort(mArray, mCurrent, sizeof(char*), compare);
- }
-
- //
- // Pass this to the sort routine to do an ascending alphabetical sort.
- //
- static int cmpAscendingAlpha(const void* pstr1, const void* pstr2) {
- return strcmp(*(const char**)pstr1, *(const char**)pstr2);
- }
-
- //
- // Get the #of items in the array.
- //
- inline int size(void) const { return mCurrent; }
-
- //
- // Return entry N.
- // [should use operator[] here]
- //
- const char* getEntry(int idx) const {
- if (idx < 0 || idx >= mCurrent)
- return NULL;
- return mArray[idx];
- }
-
- //
- // Set entry N to specified string.
- // [should use operator[] here]
- //
- void setEntry(int idx, const char* str) {
- if (idx < 0 || idx >= mCurrent)
- return;
- delete[] mArray[idx];
- int len = strlen(str);
- mArray[idx] = new char[len+1];
- memcpy(mArray[idx], str, len+1);
- }
-
-private:
- int mMax;
- int mCurrent;
- char** mArray;
-};
-
-}; // namespace android
-
-#endif // _LIBS_UTILS_STRING_ARRAY_H
diff --git a/include/utils/threads.h b/include/utils/threads.h
index b320915..e0cb664 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -199,11 +199,11 @@ public:
// constructed and released when Autolock goes out of scope.
class Autolock {
public:
- inline Autolock(Mutex& mutex) : mpMutex(&mutex) { mutex.lock(); }
- inline Autolock(Mutex* mutex) : mpMutex(mutex) { mutex->lock(); }
- inline ~Autolock() { mpMutex->unlock(); }
+ inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }
+ inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
+ inline ~Autolock() { mLock.unlock(); }
private:
- Mutex* mpMutex;
+ Mutex& mLock;
};
private:
@@ -291,7 +291,7 @@ protected:
bool exitPending() const;
private:
- // Derived class must implemtent threadLoop(). The thread starts its life
+ // Derived class must implement threadLoop(). The thread starts its life
// here. There are two ways of using the Thread object:
// 1) loop: if threadLoop() returns true, it will be called again if
// requestExit() wasn't called.
diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk
index 50d516b..874f2c4 100644
--- a/libs/audioflinger/Android.mk
+++ b/libs/audioflinger/Android.mk
@@ -11,6 +11,7 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
+ libbinder \
libmedia \
libhardware_legacy
@@ -34,6 +35,7 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
+ libbinder \
libmedia \
libhardware_legacy
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 324111b..9783e54 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -24,10 +24,10 @@
#include <sys/time.h>
#include <sys/resource.h>
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <utils/Log.h>
-#include <utils/Parcel.h>
-#include <utils/IPCThreadState.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
#include <utils/String16.h>
#include <utils/threads.h>
@@ -652,6 +652,7 @@ status_t AudioFlinger::setStreamVolume(int stream, float value)
}
status_t ret = NO_ERROR;
+
if (stream == AudioSystem::VOICE_CALL ||
stream == AudioSystem::BLUETOOTH_SCO) {
float hwValue;
@@ -668,7 +669,13 @@ status_t AudioFlinger::setStreamVolume(int stream, float value)
mHardwareStatus = AUDIO_SET_VOICE_VOLUME;
ret = mAudioHardware->setVoiceVolume(hwValue);
mHardwareStatus = AUDIO_HW_IDLE;
+
}
+
+ mHardwareMixerThread->setStreamVolume(stream, value);
+#ifdef WITH_A2DP
+ mA2dpMixerThread->setStreamVolume(stream, value);
+#endif
mHardwareMixerThread->setStreamVolume(stream, value);
#ifdef WITH_A2DP
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 8e47b29..cc3d6c2 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -30,7 +30,7 @@
#include <utils/Atomic.h>
#include <utils/Errors.h>
#include <utils/threads.h>
-#include <utils/MemoryDealer.h>
+#include <binder/MemoryDealer.h>
#include <utils/KeyedVector.h>
#include <utils/SortedVector.h>
#include <utils/Vector.h>
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk
new file mode 100644
index 0000000..c4d695e
--- /dev/null
+++ b/libs/binder/Android.mk
@@ -0,0 +1,44 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# we have the common sources, plus some device-specific stuff
+LOCAL_SRC_FILES:= \
+ Binder.cpp \
+ BpBinder.cpp \
+ IInterface.cpp \
+ IMemory.cpp \
+ IPCThreadState.cpp \
+ IPermissionController.cpp \
+ IServiceManager.cpp \
+ MemoryDealer.cpp \
+ MemoryBase.cpp \
+ MemoryHeapBase.cpp \
+ MemoryHeapPmem.cpp \
+ Parcel.cpp \
+ ProcessState.cpp \
+ Static.cpp
+
+LOCAL_LDLIBS += -lpthread
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libcutils \
+ libutils
+
+LOCAL_MODULE:= libbinder
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/utils/Binder.cpp b/libs/binder/Binder.cpp
index 37e4685..0dd7622 100644
--- a/libs/utils/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-#include <utils/Binder.h>
+#include <binder/Binder.h>
#include <utils/Atomic.h>
-#include <utils/BpBinder.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/BpBinder.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
#include <stdio.h>
@@ -27,6 +27,17 @@ namespace android {
// ---------------------------------------------------------------------------
+IBinder::IBinder()
+ : RefBase()
+{
+}
+
+IBinder::~IBinder()
+{
+}
+
+// ---------------------------------------------------------------------------
+
sp<IInterface> IBinder::queryLocalInterface(const String16& descriptor)
{
return NULL;
@@ -58,6 +69,8 @@ public:
// ---------------------------------------------------------------------------
+String16 BBinder::sEmptyDescriptor;
+
BBinder::BBinder()
: mExtras(NULL)
{
@@ -73,10 +86,10 @@ status_t BBinder::pingBinder()
return NO_ERROR;
}
-String16 BBinder::getInterfaceDescriptor() const
+const String16& BBinder::getInterfaceDescriptor() const
{
LOGW("reached BBinder::getInterfaceDescriptor (this=%p)", this);
- return String16();
+ return sEmptyDescriptor;
}
status_t BBinder::transact(
diff --git a/libs/utils/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 69ab195..5de87ec 100644
--- a/libs/utils/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -17,9 +17,9 @@
#define LOG_TAG "BpBinder"
//#define LOG_NDEBUG 0
-#include <utils/BpBinder.h>
+#include <binder/BpBinder.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IPCThreadState.h>
#include <utils/Log.h>
#include <stdio.h>
@@ -98,16 +98,33 @@ BpBinder::BpBinder(int32_t handle)
IPCThreadState::self()->incWeakHandle(handle);
}
-String16 BpBinder::getInterfaceDescriptor() const
+bool BpBinder::isDescriptorCached() const {
+ Mutex::Autolock _l(mLock);
+ return mDescriptorCache.size() ? true : false;
+}
+
+const String16& BpBinder::getInterfaceDescriptor() const
{
- String16 res;
- Parcel send, reply;
- status_t err = const_cast<BpBinder*>(this)->transact(
- INTERFACE_TRANSACTION, send, &reply);
- if (err == NO_ERROR) {
- res = reply.readString16();
+ if (isDescriptorCached() == false) {
+ Parcel send, reply;
+ // do the IPC without a lock held.
+ status_t err = const_cast<BpBinder*>(this)->transact(
+ INTERFACE_TRANSACTION, send, &reply);
+ if (err == NO_ERROR) {
+ String16 res(reply.readString16());
+ Mutex::Autolock _l(mLock);
+ // mDescriptorCache could have been assigned while the lock was
+ // released.
+ if (mDescriptorCache.size() == 0)
+ mDescriptorCache = res;
+ }
}
- return res;
+
+ // we're returning a reference to a non-static object here. Usually this
+ // is not something smart to do, however, with binder objects it is
+ // (usually) safe because they are reference-counted.
+
+ return mDescriptorCache;
}
bool BpBinder::isBinderAlive() const
diff --git a/libs/utils/IInterface.cpp b/libs/binder/IInterface.cpp
index 6ea8178..29acf5d 100644
--- a/libs/utils/IInterface.cpp
+++ b/libs/binder/IInterface.cpp
@@ -14,12 +14,19 @@
* limitations under the License.
*/
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
namespace android {
// ---------------------------------------------------------------------------
+IInterface::IInterface()
+ : RefBase() {
+}
+
+IInterface::~IInterface() {
+}
+
sp<IBinder> IInterface::asBinder()
{
return this ? onAsBinder() : NULL;
diff --git a/libs/utils/IMemory.cpp b/libs/binder/IMemory.cpp
index 429bc2b..6c1d225 100644
--- a/libs/utils/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -25,11 +25,11 @@
#include <sys/types.h>
#include <sys/mman.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
#include <utils/Atomic.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <utils/CallStack.h>
#define VERBOSE 0
@@ -205,11 +205,11 @@ sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const
IMPLEMENT_META_INTERFACE(Memory, "android.utils.IMemory");
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
+BnMemory::BnMemory() {
+}
+
+BnMemory::~BnMemory() {
+}
status_t BnMemory::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
@@ -299,11 +299,11 @@ void BpMemoryHeap::assertReallyMapped() const
ssize_t size = reply.readInt32();
uint32_t flags = reply.readInt32();
- LOGE_IF(err, "binder=%p transaction failed fd=%d, size=%d, err=%d (%s)",
+ LOGE_IF(err, "binder=%p transaction failed fd=%d, size=%ld, err=%d (%s)",
asBinder().get(), parcel_fd, size, err, strerror(-err));
int fd = dup( parcel_fd );
- LOGE_IF(fd==-1, "cannot dup fd=%d, size=%d, err=%d (%s)",
+ LOGE_IF(fd==-1, "cannot dup fd=%d, size=%ld, err=%d (%s)",
parcel_fd, size, err, strerror(errno));
int access = PROT_READ;
@@ -316,7 +316,7 @@ void BpMemoryHeap::assertReallyMapped() const
mRealHeap = true;
mBase = mmap(0, size, access, MAP_SHARED, fd, 0);
if (mBase == MAP_FAILED) {
- LOGE("cannot map BpMemoryHeap (binder=%p), size=%d, fd=%d (%s)",
+ LOGE("cannot map BpMemoryHeap (binder=%p), size=%ld, fd=%d (%s)",
asBinder().get(), size, fd, strerror(errno));
close(fd);
} else {
@@ -357,8 +357,14 @@ uint32_t BpMemoryHeap::getFlags() const {
IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap");
+BnMemoryHeap::BnMemoryHeap() {
+}
+
+BnMemoryHeap::~BnMemoryHeap() {
+}
+
status_t BnMemoryHeap::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case HEAP_ID: {
diff --git a/libs/utils/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 04ae142..c3889e9 100644
--- a/libs/utils/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-#include <utils/IPCThreadState.h>
+#include <binder/IPCThreadState.h>
-#include <utils/Binder.h>
-#include <utils/BpBinder.h>
+#include <binder/Binder.h>
+#include <binder/BpBinder.h>
#include <utils/Debug.h>
#include <utils/Log.h>
#include <utils/TextOutput.h>
#include <utils/threads.h>
-#include <private/utils/binder_module.h>
-#include <private/utils/Static.h>
+#include <private/binder/binder_module.h>
+#include <private/binder/Static.h>
#include <sys/ioctl.h>
#include <signal.h>
diff --git a/libs/utils/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
index f01d38f..bff4c9b 100644
--- a/libs/utils/IPermissionController.cpp
+++ b/libs/binder/IPermissionController.cpp
@@ -16,14 +16,14 @@
#define LOG_TAG "PermissionController"
-#include <utils/IPermissionController.h>
+#include <binder/IPermissionController.h>
#include <utils/Debug.h>
#include <utils/Log.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <utils/String8.h>
-#include <private/utils/Static.h>
+#include <private/binder/Static.h>
namespace android {
@@ -55,12 +55,6 @@ IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnPermissionController::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/utils/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 9beeadd..88774e7 100644
--- a/libs/utils/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -16,16 +16,16 @@
#define LOG_TAG "ServiceManager"
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <utils/Debug.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IPCThreadState.h>
#include <utils/Log.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <utils/String8.h>
#include <utils/SystemClock.h>
-#include <private/utils/Static.h>
+#include <private/binder/Static.h>
#include <unistd.h>
@@ -178,12 +178,6 @@ IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnServiceManager::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/utils/MemoryBase.cpp b/libs/binder/MemoryBase.cpp
index f25e11c..033066b 100644
--- a/libs/utils/MemoryBase.cpp
+++ b/libs/binder/MemoryBase.cpp
@@ -18,7 +18,7 @@
#include <stdlib.h>
#include <stdint.h>
-#include <utils/MemoryBase.h>
+#include <binder/MemoryBase.h>
namespace android {
diff --git a/libs/utils/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
index cf8201b..d5ffe7f 100644
--- a/libs/utils/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -16,13 +16,13 @@
#define LOG_TAG "MemoryDealer"
-#include <utils/MemoryDealer.h>
+#include <binder/MemoryDealer.h>
#include <utils/Log.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IPCThreadState.h>
#include <utils/SortedVector.h>
#include <utils/String8.h>
-#include <utils/MemoryBase.h>
+#include <binder/MemoryBase.h>
#include <stdint.h>
#include <stdio.h>
@@ -38,7 +38,15 @@
#include <sys/file.h>
namespace android {
+// ----------------------------------------------------------------------------
+HeapInterface::HeapInterface() { }
+HeapInterface::~HeapInterface() { }
+
+// ----------------------------------------------------------------------------
+
+AllocatorInterface::AllocatorInterface() { }
+AllocatorInterface::~AllocatorInterface() { }
// ----------------------------------------------------------------------------
@@ -107,7 +115,7 @@ sp<IMemory> MemoryDealer::allocate(size_t size, uint32_t flags)
if (new_memory != 0) {
memory = new Allocation(this, offset, size, new_memory);
} else {
- LOGE("couldn't map [%8x, %d]", offset, size);
+ LOGE("couldn't map [%8lx, %u]", offset, size);
if (size) {
/* NOTE: it's VERY important to not free allocations of size 0
* because they're special as they don't have any record in the
@@ -339,6 +347,10 @@ void SimpleBestFitAllocator::dump_l(String8& result,
// ----------------------------------------------------------------------------
+SharedHeap::SharedHeap()
+ : HeapInterface(), MemoryHeapBase()
+{
+}
SharedHeap::SharedHeap(size_t size, uint32_t flags, char const * name)
: MemoryHeapBase(size, flags, name)
diff --git a/libs/utils/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index 8251728..ac38f51 100644
--- a/libs/utils/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -29,7 +29,7 @@
#include <cutils/ashmem.h>
#include <cutils/atomic.h>
-#include <utils/MemoryHeapBase.h>
+#include <binder/MemoryHeapBase.h>
#if HAVE_ANDROID_OS
#include <linux/android_pmem.h>
diff --git a/libs/utils/MemoryHeapPmem.cpp b/libs/binder/MemoryHeapPmem.cpp
index eba2b30..3806a42 100644
--- a/libs/utils/MemoryHeapPmem.cpp
+++ b/libs/binder/MemoryHeapPmem.cpp
@@ -27,8 +27,8 @@
#include <cutils/log.h>
-#include <utils/MemoryHeapPmem.h>
-#include <utils/MemoryHeapBase.h>
+#include <binder/MemoryHeapPmem.h>
+#include <binder/MemoryHeapBase.h>
#if HAVE_ANDROID_OS
#include <linux/android_pmem.h>
@@ -108,7 +108,7 @@ void SubRegionMemory::revoke()
// promote() it.
#if HAVE_ANDROID_OS
- if (mSize != NULL) {
+ if (mSize != 0) {
const sp<MemoryHeapPmem>& heap(getHeap());
int our_fd = heap->heapID();
struct pmem_region sub;
diff --git a/libs/utils/Parcel.cpp b/libs/binder/Parcel.cpp
index b0e3750..f40e4bd 100644
--- a/libs/utils/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -17,19 +17,19 @@
#define LOG_TAG "Parcel"
//#define LOG_NDEBUG 0
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
-#include <utils/Binder.h>
-#include <utils/BpBinder.h>
+#include <binder/Binder.h>
+#include <binder/BpBinder.h>
#include <utils/Debug.h>
-#include <utils/ProcessState.h>
+#include <binder/ProcessState.h>
#include <utils/Log.h>
#include <utils/String8.h>
#include <utils/String16.h>
#include <utils/TextOutput.h>
#include <utils/misc.h>
-#include <private/utils/binder_module.h>
+#include <private/binder/binder_module.h>
#include <stdio.h>
#include <stdlib.h>
@@ -441,9 +441,14 @@ status_t Parcel::writeInterfaceToken(const String16& interface)
return writeString16(interface);
}
+bool Parcel::checkInterface(IBinder* binder) const
+{
+ return enforceInterface(binder->getInterfaceDescriptor());
+}
+
bool Parcel::enforceInterface(const String16& interface) const
{
- String16 str = readString16();
+ const String16 str(readString16());
if (str == interface) {
return true;
} else {
diff --git a/libs/utils/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 4567df6..d7daf73 100644
--- a/libs/utils/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -18,19 +18,19 @@
#include <cutils/process_name.h>
-#include <utils/ProcessState.h>
+#include <binder/ProcessState.h>
#include <utils/Atomic.h>
-#include <utils/BpBinder.h>
-#include <utils/IPCThreadState.h>
+#include <binder/BpBinder.h>
+#include <binder/IPCThreadState.h>
#include <utils/Log.h>
#include <utils/String8.h>
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <utils/String8.h>
#include <utils/threads.h>
-#include <private/utils/binder_module.h>
-#include <private/utils/Static.h>
+#include <private/binder/binder_module.h>
+#include <private/binder/Static.h>
#include <errno.h>
#include <fcntl.h>
diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp
new file mode 100644
index 0000000..12b0308
--- /dev/null
+++ b/libs/binder/Static.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// All static variables go here, to control initialization and
+// destruction order in the library.
+
+#include <private/binder/Static.h>
+
+#include <binder/IPCThreadState.h>
+#include <utils/Log.h>
+
+namespace android {
+
+// ------------ ProcessState.cpp
+
+Mutex gProcessMutex;
+sp<ProcessState> gProcess;
+
+class LibUtilsIPCtStatics
+{
+public:
+ LibUtilsIPCtStatics()
+ {
+ }
+
+ ~LibUtilsIPCtStatics()
+ {
+ IPCThreadState::shutdown();
+ }
+};
+
+static LibUtilsIPCtStatics gIPCStatics;
+
+// ------------ ServiceManager.cpp
+
+Mutex gDefaultServiceManagerLock;
+sp<IServiceManager> gDefaultServiceManager;
+sp<IPermissionController> gPermissionController;
+
+} // namespace android
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
new file mode 100644
index 0000000..6ff39a4
--- /dev/null
+++ b/libs/rs/Android.mk
@@ -0,0 +1,143 @@
+# Only build if BUILD_RENDERSCRIPT is defined to true in the environment.
+ifeq ($(BUILD_RENDERSCRIPT),true)
+
+TOP_LOCAL_PATH:=$(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_PATH:= $(TOP_LOCAL_PATH)
+
+# Build rsg-generator
+
+LOCAL_MODULE := rsg-generator
+
+# These symbols are normally defined by BUILD_XXX, but we need to define them
+# here so that local-intermediates-dir works.
+
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE_CLASS := EXECUTABLES
+intermediates:= $(local-intermediates-dir)
+
+GEN := $(addprefix $(intermediates)/, \
+ lex.yy.c \
+ )
+$(GEN): PRIVATE_CUSTOM_TOOL = flex -o $@ $<
+
+$(intermediates)/lex.yy.c : $(LOCAL_PATH)/spec.lex
+ $(transform-generated-source)
+
+$(LOCAL_PATH)/rsg_generator.c : $(intermediates)/lex.yy.c
+
+LOCAL_SRC_FILES:= \
+ rsg_generator.c
+
+include $(BUILD_HOST_EXECUTABLE)
+
+RSG_GENERATOR:=$(LOCAL_BUILT_MODULE)
+
+# Build render script lib
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libRS
+
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+intermediates:= $(local-intermediates-dir)
+
+RS_GENERATED_INCLUDE_DIR:=$(intermediates)
+
+# Generate custom headers
+
+GEN := $(addprefix $(intermediates)/, \
+ rsgApiStructs.h \
+ rsgApiFuncDecl.h \
+ )
+
+$(GEN) : PRIVATE_CUSTOM_TOOL = $(RSG_GENERATOR) $< $@ <$(TOP_LOCAL_PATH)/rs.spec
+$(GEN) : $(RSG_GENERATOR) $(LOCAL_PATH)/rs.spec
+$(GEN): $(intermediates)/%.h : $(LOCAL_PATH)/%.h.rsg
+ $(transform-generated-source)
+
+RS_GENERATED_SOURCES += $(GEN)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+# Generate custom source files
+
+GEN := $(addprefix $(intermediates)/, \
+ rsgApi.cpp \
+ rsgApiReplay.cpp \
+ )
+
+$(GEN) : PRIVATE_CUSTOM_TOOL = $(RSG_GENERATOR) $< $@ <$(TOP_LOCAL_PATH)/rs.spec
+$(GEN) : $(RSG_GENERATOR) $(LOCAL_PATH)/rs.spec
+$(GEN): $(intermediates)/%.cpp : $(LOCAL_PATH)/%.cpp.rsg
+ $(transform-generated-source)
+
+RS_GENERATED_SOURCES += $(GEN)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+LOCAL_SRC_FILES:= \
+ rsAdapter.cpp \
+ rsAllocation.cpp \
+ rsComponent.cpp \
+ rsContext.cpp \
+ rsDevice.cpp \
+ rsElement.cpp \
+ rsLocklessFifo.cpp \
+ rsObjectBase.cpp \
+ rsMatrix.cpp \
+ rsProgram.cpp \
+ rsProgramFragment.cpp \
+ rsProgramFragmentStore.cpp \
+ rsProgramVertex.cpp \
+ rsSampler.cpp \
+ rsScript.cpp \
+ rsScriptC.cpp \
+ rsThreadIO.cpp \
+ rsType.cpp \
+ rsTriangleMesh.cpp
+
+LOCAL_SHARED_LIBRARIES += libcutils libutils libEGL libGLESv1_CM libui libacc
+LOCAL_LDLIBS := -lpthread -ldl
+LOCAL_MODULE:= libRS
+LOCAL_PRELINK_MODULE := false
+
+#LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Build JNI library
+
+LOCAL_PATH:= $(TOP_LOCAL_PATH)/jni
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ RenderScript_jni.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libandroid_runtime \
+ libacc \
+ libnativehelper \
+ libRS \
+ libcutils \
+ libsgl \
+ libutils \
+ libui
+
+LOCAL_STATIC_LIBRARIES :=
+
+LOCAL_C_INCLUDES += \
+ $(JNI_H_INCLUDE) \
+ $(RS_GENERATED_INCLUDE_DIR) \
+ $(call include-path-for, corecg graphics)
+
+LOCAL_CFLAGS +=
+
+LOCAL_LDLIBS := -lpthread
+
+LOCAL_MODULE:= libRS_jni
+LOCAL_PRELINK_MODULE := false
+
+LOCAL_ADDITIONAL_DEPENDENCIES += $(RS_GENERATED_SOURCES)
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(call all-subdir-makefiles)
+endif # BUILD_RENDERSCRIPT
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
new file mode 100644
index 0000000..2b33419
--- /dev/null
+++ b/libs/rs/RenderScript.h
@@ -0,0 +1,186 @@
+/*
+ * 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.
+ */
+
+#ifndef RENDER_SCRIPT_H
+#define RENDER_SCRIPT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//////////////////////////////////////////////////////
+//
+
+typedef void * RsAdapter1D;
+typedef void * RsAdapter2D;
+typedef void * RsAllocation;
+typedef void * RsContext;
+typedef void * RsDevice;
+typedef void * RsElement;
+typedef void * RsSampler;
+typedef void * RsScript;
+typedef void * RsScriptBasicTemp;
+typedef void * RsTriangleMesh;
+typedef void * RsType;
+
+typedef void * RsProgramVertex;
+typedef void * RsProgramFragment;
+typedef void * RsProgramFragmentStore;
+
+RsDevice rsDeviceCreate();
+void rsDeviceDestroy(RsDevice);
+
+RsContext rsContextCreate(RsDevice, void *, uint32_t version);
+void rsContextDestroy(RsContext);
+
+enum RsDataType {
+ RS_TYPE_FLOAT,
+ RS_TYPE_UNSIGNED,
+ RS_TYPE_SIGNED
+};
+
+enum RsDataKind {
+ RS_KIND_USER,
+ RS_KIND_RED,
+ RS_KIND_GREEN,
+ RS_KIND_BLUE,
+ RS_KIND_ALPHA,
+ RS_KIND_LUMINANCE,
+ RS_KIND_INTENSITY,
+ RS_KIND_X,
+ RS_KIND_Y,
+ RS_KIND_Z,
+ RS_KIND_W,
+ RS_KIND_S,
+ RS_KIND_T,
+ RS_KIND_Q,
+ RS_KIND_R,
+ RS_KIND_NX,
+ RS_KIND_NY,
+ RS_KIND_NZ,
+ RS_KIND_INDEX
+};
+
+enum RsElementPredefined {
+ RS_ELEMENT_USER_U8,
+ RS_ELEMENT_USER_I8,
+ RS_ELEMENT_USER_U16,
+ RS_ELEMENT_USER_I16,
+ RS_ELEMENT_USER_U32,
+ RS_ELEMENT_USER_I32,
+ RS_ELEMENT_USER_FLOAT,
+
+ RS_ELEMENT_A_8, // 7
+ RS_ELEMENT_RGB_565, // 8
+ RS_ELEMENT_RGBA_5551, // 9
+ RS_ELEMENT_RGBA_4444, // 10
+ RS_ELEMENT_RGB_888, // 11
+ RS_ELEMENT_RGBA_8888, // 12
+
+ RS_ELEMENT_INDEX_16, //13
+ RS_ELEMENT_INDEX_32,
+ RS_ELEMENT_XY_F32,
+ RS_ELEMENT_XYZ_F32,
+ RS_ELEMENT_ST_XY_F32,
+ RS_ELEMENT_ST_XYZ_F32,
+ RS_ELEMENT_NORM_XYZ_F32,
+ RS_ELEMENT_NORM_ST_XYZ_F32,
+};
+
+enum RsSamplerParam {
+ RS_SAMPLER_MIN_FILTER,
+ RS_SAMPLER_MAG_FILTER,
+ RS_SAMPLER_WRAP_S,
+ RS_SAMPLER_WRAP_T,
+ RS_SAMPLER_WRAP_R
+};
+
+enum RsSamplerValue {
+ RS_SAMPLER_NEAREST,
+ RS_SAMPLER_LINEAR,
+ RS_SAMPLER_LINEAR_MIP_LINEAR,
+ RS_SAMPLER_WRAP,
+ RS_SAMPLER_CLAMP
+};
+
+enum RsDimension {
+ RS_DIMENSION_X,
+ RS_DIMENSION_Y,
+ RS_DIMENSION_Z,
+ RS_DIMENSION_LOD,
+ RS_DIMENSION_FACE,
+
+ RS_DIMENSION_ARRAY_0 = 100,
+ RS_DIMENSION_ARRAY_1,
+ RS_DIMENSION_ARRAY_2,
+ RS_DIMENSION_ARRAY_3,
+ RS_DIMENSION_MAX = RS_DIMENSION_ARRAY_3
+};
+
+enum RsDepthFunc {
+ RS_DEPTH_FUNC_ALWAYS,
+ RS_DEPTH_FUNC_LESS,
+ RS_DEPTH_FUNC_LEQUAL,
+ RS_DEPTH_FUNC_GREATER,
+ RS_DEPTH_FUNC_GEQUAL,
+ RS_DEPTH_FUNC_EQUAL,
+ RS_DEPTH_FUNC_NOTEQUAL
+};
+
+enum RsBlendSrcFunc {
+ RS_BLEND_SRC_ZERO,
+ RS_BLEND_SRC_ONE,
+ RS_BLEND_SRC_DST_COLOR,
+ RS_BLEND_SRC_ONE_MINUS_DST_COLOR,
+ RS_BLEND_SRC_SRC_ALPHA,
+ RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA,
+ RS_BLEND_SRC_DST_ALPHA,
+ RS_BLEND_SRC_ONE_MINUS_DST_ALPHA,
+ RS_BLEND_SRC_SRC_ALPHA_SATURATE
+};
+
+enum RsBlendDstFunc {
+ RS_BLEND_DST_ZERO,
+ RS_BLEND_DST_ONE,
+ RS_BLEND_DST_SRC_COLOR,
+ RS_BLEND_DST_ONE_MINUS_SRC_COLOR,
+ RS_BLEND_DST_SRC_ALPHA,
+ RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
+ RS_BLEND_DST_DST_ALPHA,
+ RS_BLEND_DST_ONE_MINUS_DST_ALPHA
+};
+
+enum RsTexEnvMode {
+ RS_TEX_ENV_MODE_REPLACE,
+ RS_TEX_ENV_MODE_MODULATE,
+ RS_TEX_ENV_MODE_DECAL
+};
+
+
+
+#include "rsgApiFuncDecl.h"
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // RENDER_SCRIPT_H
+
+
+
diff --git a/libs/rs/RenderScriptEnv.h b/libs/rs/RenderScriptEnv.h
new file mode 100644
index 0000000..1bf5f22
--- /dev/null
+++ b/libs/rs/RenderScriptEnv.h
@@ -0,0 +1,97 @@
+#include <stdint.h>
+
+
+typedef void * RsAdapter1D;
+typedef void * RsAdapter2D;
+typedef void * RsAllocation;
+typedef void * RsContext;
+typedef void * RsDevice;
+typedef void * RsElement;
+typedef void * RsSampler;
+typedef void * RsScript;
+typedef void * RsScriptBasicTemp;
+typedef void * RsTriangleMesh;
+typedef void * RsType;
+typedef void * RsProgramFragment;
+typedef void * RsProgramFragmentStore;
+
+
+typedef struct {
+ float m[16];
+} rsc_Matrix;
+
+
+typedef struct {
+ float v[4];
+} rsc_Vector4;
+
+#define RS_PROGRAM_VERTEX_MODELVIEW_OFFSET 0
+#define RS_PROGRAM_VERTEX_PROJECTION_OFFSET 16
+#define RS_PROGRAM_VERTEX_TEXTURE_OFFSET 32
+
+typedef struct {
+ const void * (*loadEnvVp)(void *con, uint32_t bank, uint32_t offset);
+
+ float (*loadEnvF)(void *con, uint32_t bank, uint32_t offset);
+ int32_t (*loadEnvI32)(void *con, uint32_t bank, uint32_t offset);
+ uint32_t (*loadEnvU32)(void *con, uint32_t bank, uint32_t offset);
+ void (*loadEnvVec4)(void *con, uint32_t bank, uint32_t offset, rsc_Vector4 *);
+ void (*loadEnvMatrix)(void *con, uint32_t bank, uint32_t offset, rsc_Matrix *);
+
+ void (*storeEnvF)(void *con, uint32_t bank, uint32_t offset, float);
+ void (*storeEnvI32)(void *con, uint32_t bank, uint32_t offset, int32_t);
+ void (*storeEnvU32)(void *con, uint32_t bank, uint32_t offset, uint32_t);
+ void (*storeEnvVec4)(void *con, uint32_t bank, uint32_t offset, const rsc_Vector4 *);
+ void (*storeEnvMatrix)(void *con, uint32_t bank, uint32_t offset, const rsc_Matrix *);
+
+ void (*matrixLoadIdentity)(void *con, rsc_Matrix *);
+ void (*matrixLoadFloat)(void *con, rsc_Matrix *, const float *);
+ void (*matrixLoadMat)(void *con, rsc_Matrix *, const rsc_Matrix *);
+ void (*matrixLoadRotate)(void *con, rsc_Matrix *, float rot, float x, float y, float z);
+ void (*matrixLoadScale)(void *con, rsc_Matrix *, float x, float y, float z);
+ void (*matrixLoadTranslate)(void *con, rsc_Matrix *, float x, float y, float z);
+ void (*matrixLoadMultiply)(void *con, rsc_Matrix *, const rsc_Matrix *lhs, const rsc_Matrix *rhs);
+ void (*matrixMultiply)(void *con, rsc_Matrix *, const rsc_Matrix *rhs);
+ void (*matrixRotate)(void *con, rsc_Matrix *, float rot, float x, float y, float z);
+ void (*matrixScale)(void *con, rsc_Matrix *, float x, float y, float z);
+ void (*matrixTranslate)(void *con, rsc_Matrix *, float x, float y, float z);
+
+ void (*color)(void *con, float r, float g, float b, float a);
+
+ void (*programFragmentBindTexture)(void *con, RsProgramFragment, uint32_t slot, RsAllocation);
+ void (*programFragmentBindSampler)(void *con, RsProgramFragment, uint32_t slot, RsAllocation);
+
+ void (*materialDiffuse)(void *con, float r, float g, float b, float a);
+ void (*materialSpecular)(void *con, float r, float g, float b, float a);
+ void (*lightPosition)(void *con, float x, float y, float z, float w);
+ void (*materialShininess)(void *con, float s);
+
+ void (*uploadToTexture)(void *con, RsAllocation va, uint32_t baseMipLevel);
+
+ void (*enable)(void *con, uint32_t);
+ void (*disable)(void *con, uint32_t);
+
+ uint32_t (*rand)(void *con, uint32_t max);
+
+ void (*contextBindProgramFragment)(void *con, RsProgramFragment pf);
+ void (*contextBindProgramFragmentStore)(void *con, RsProgramFragmentStore pfs);
+
+
+ // Drawing funcs
+ void (*renderTriangleMesh)(void *con, RsTriangleMesh);
+ void (*renderTriangleMeshRange)(void *con, RsTriangleMesh, uint32_t start, uint32_t count);
+
+ // Assumes (GL_FIXED) x,y,z (GL_UNSIGNED_BYTE)r,g,b,a
+ void (*drawTriangleArray)(void *con, RsAllocation alloc, uint32_t count);
+
+ void (*drawRect)(void *con, int32_t x1, int32_t x2, int32_t y1, int32_t y2);
+} rsc_FunctionTable;
+
+typedef int (*rsc_RunScript)(void *con, const rsc_FunctionTable *, uint32_t launchID);
+
+
+/* EnableCap */
+#define GL_LIGHTING 0x0B50
+
+/* LightName */
+#define GL_LIGHT0 0x4000
diff --git a/libs/rs/java/Android.mk b/libs/rs/java/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/libs/rs/java/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/libs/rs/java/Fountain/Android.mk b/libs/rs/java/Fountain/Android.mk
new file mode 100644
index 0000000..cf08467
--- /dev/null
+++ b/libs/rs/java/Fountain/Android.mk
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := Fountain
+
+include $(BUILD_PACKAGE)
+##################################################
+include $(CLEAR_VARS)
+
+include $(BUILD_MULTI_PREBUILT)
+
+# Use the folloing include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libs/rs/java/Fountain/AndroidManifest.xml b/libs/rs/java/Fountain/AndroidManifest.xml
new file mode 100644
index 0000000..a10938b
--- /dev/null
+++ b/libs/rs/java/Fountain/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.fountain">
+ <application android:label="Fountain">
+ <activity android:name="Fountain"
+ android:theme="@android:style/Theme.Black.NoTitleBar">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/libs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.png b/libs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.png
new file mode 100755
index 0000000..e91bfb4
--- /dev/null
+++ b/libs/rs/java/Fountain/res/drawable/gadgets_clock_mp3.png
Binary files differ
diff --git a/libs/rs/java/Fountain/res/raw/fountain.c b/libs/rs/java/Fountain/res/raw/fountain.c
new file mode 100644
index 0000000..8b473ab
--- /dev/null
+++ b/libs/rs/java/Fountain/res/raw/fountain.c
@@ -0,0 +1,104 @@
+// Fountain test script
+
+int main(void* con, int ft, int launchID) {
+ int count, touch, x, y, rate, maxLife, lifeShift;
+ int life;
+ int ct, ct2;
+ int newPart;
+ int drawCount;
+ int dx, dy, idx;
+ int posx,posy;
+ int c;
+ int srcIdx;
+ int dstIdx;
+
+ count = loadI32(con, 0, 1);
+ touch = loadI32(con, 0, 2);
+ x = loadI32(con, 0, 3);
+ y = loadI32(con, 0, 4);
+
+ rate = 4;
+ maxLife = (count / rate) - 1;
+ lifeShift = 0;
+ {
+ life = maxLife;
+ while (life > 255) {
+ life = life >> 1;
+ lifeShift ++;
+ }
+ }
+
+ contextBindProgramFragment(con, loadI32(con, 0, 7));
+ drawRect(con, 0, 256, 0, 512);
+ contextBindProgramFragment(con, loadI32(con, 0, 6));
+
+ if (touch) {
+ newPart = loadI32(con, 2, 0);
+ for (ct2=0; ct2<rate; ct2++) {
+ dx = scriptRand(con, 0x10000) - 0x8000;
+ dy = scriptRand(con, 0x10000) - 0x8000;
+
+ idx = newPart * 5 + 1;
+ storeI32(con, 2, idx, dx);
+ storeI32(con, 2, idx + 1, dy);
+ storeI32(con, 2, idx + 2, maxLife);
+ storeI32(con, 2, idx + 3, x << 16);
+ storeI32(con, 2, idx + 4, y << 16);
+
+ newPart++;
+ if (newPart >= count) {
+ newPart = 0;
+ }
+ }
+ storeI32(con, 2, 0, newPart);
+ }
+
+ drawCount = 0;
+ for (ct=0; ct < count; ct++) {
+ srcIdx = ct * 5 + 1;
+
+ dx = loadI32(con, 2, srcIdx);
+ dy = loadI32(con, 2, srcIdx + 1);
+ life = loadI32(con, 2, srcIdx + 2);
+ posx = loadI32(con, 2, srcIdx + 3);
+ posy = loadI32(con, 2, srcIdx + 4);
+
+ if (life) {
+ if (posy < (480 << 16)) {
+ dstIdx = drawCount * 9;
+ c = 0xffafcf | ((life >> lifeShift) << 24);
+
+ storeU32(con, 1, dstIdx, c);
+ storeI32(con, 1, dstIdx + 1, posx);
+ storeI32(con, 1, dstIdx + 2, posy);
+
+ storeU32(con, 1, dstIdx + 3, c);
+ storeI32(con, 1, dstIdx + 4, posx + 0x10000);
+ storeI32(con, 1, dstIdx + 5, posy + dy * 4);
+
+ storeU32(con, 1, dstIdx + 6, c);
+ storeI32(con, 1, dstIdx + 7, posx - 0x10000);
+ storeI32(con, 1, dstIdx + 8, posy + dy * 4);
+ drawCount ++;
+ } else {
+ if (dy > 0) {
+ dy = (-dy) >> 1;
+ }
+ }
+
+ posx = posx + dx;
+ posy = posy + dy;
+ dy = dy + 0x400;
+ life --;
+
+ //storeI32(con, 2, srcIdx, dx);
+ storeI32(con, 2, srcIdx + 1, dy);
+ storeI32(con, 2, srcIdx + 2, life);
+ storeI32(con, 2, srcIdx + 3, posx);
+ storeI32(con, 2, srcIdx + 4, posy);
+ }
+ }
+
+ drawTriangleArray(con, loadI32(con, 0, 5), drawCount);
+ return 1;
+}
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/Fountain.java b/libs/rs/java/Fountain/src/com/android/fountain/Fountain.java
new file mode 100644
index 0000000..0d66966
--- /dev/null
+++ b/libs/rs/java/Fountain/src/com/android/fountain/Fountain.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.fountain;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Config;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+
+import java.lang.Runtime;
+
+public class Fountain extends Activity {
+ //EventListener mListener = new EventListener();
+
+ private static final String LOG_TAG = "libRS_jni";
+ private static final boolean DEBUG = false;
+ private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
+
+ private FountainView mView;
+
+ // get the current looper (from your Activity UI thread for instance
+
+
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Create our Preview view and set it as the content of our
+ // Activity
+ mView = new FountainView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onResume();
+ mView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onPause();
+ mView.onPause();
+
+ Runtime.getRuntime().exit(0);
+ }
+
+
+ static void log(String message) {
+ if (LOG_ENABLED) {
+ Log.v(LOG_TAG, message);
+ }
+ }
+
+
+}
+
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java
new file mode 100644
index 0000000..3381525
--- /dev/null
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.fountain;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+public class FountainView extends RSSurfaceView {
+
+ public FountainView(Context context) {
+ super(context);
+
+ //setFocusable(true);
+ }
+
+ private RenderScript mRS;
+ private RenderScript.Allocation mIntAlloc;
+ private RenderScript.Allocation mPartAlloc;
+ private RenderScript.Allocation mVertAlloc;
+ private RenderScript.Script mScript;
+ private RenderScript.ProgramFragmentStore mPFS;
+ private RenderScript.ProgramFragment mPF;
+ private RenderScript.ProgramFragment mPF2;
+ private RenderScript.Allocation mTexture;
+ private RenderScript.Sampler mSampler;
+
+ private Bitmap mBackground;
+
+ int mParams[] = new int[10];
+
+ private void initRS() {
+ mRS = createRenderScript();
+
+ int partCount = 1024;
+
+ mIntAlloc = mRS.allocationCreatePredefSized(RenderScript.ElementPredefined.USER_I32, 10);
+ mPartAlloc = mRS.allocationCreatePredefSized(RenderScript.ElementPredefined.USER_I32, partCount * 3 * 3);
+ mVertAlloc = mRS.allocationCreatePredefSized(RenderScript.ElementPredefined.USER_I32, partCount * 5 + 1);
+
+ {
+ Resources res = getResources();
+ Drawable d = res.getDrawable(R.drawable.gadgets_clock_mp3);
+ BitmapDrawable bd = (BitmapDrawable)d;
+ Bitmap b = bd.getBitmap();
+ mTexture = mRS.allocationCreateFromBitmap(b,
+ RenderScript.ElementPredefined.RGB_565,
+ true);
+ mTexture.uploadToTexture(0);
+ }
+
+ mRS.programFragmentStoreBegin(null, null);
+ mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.SRC_ALPHA, RenderScript.BlendDstFunc.ONE);
+ mRS.programFragmentStoreDepthFunc(RenderScript.DepthFunc.ALWAYS);
+ mPFS = mRS.programFragmentStoreCreate();
+ mRS.contextBindProgramFragmentStore(mPFS);
+
+ mRS.samplerBegin();
+ mRS.samplerSet(RenderScript.SamplerParam.FILTER_MAG, RenderScript.SamplerValue.LINEAR);
+ mRS.samplerSet(RenderScript.SamplerParam.FILTER_MIN, RenderScript.SamplerValue.LINEAR);
+ mSampler = mRS.samplerCreate();
+
+
+ mRS.programFragmentBegin(null, null);
+ mPF = mRS.programFragmentCreate();
+ //mRS.contextBindProgramFragment(mPF);
+
+ mRS.programFragmentBegin(null, null);
+ mRS.programFragmentSetTexEnable(0, true);
+ mPF2 = mRS.programFragmentCreate();
+ mRS.contextBindProgramFragment(mPF2);
+ mPF2.bindTexture(mTexture, 0);
+ mPF2.bindSampler(mSampler, 0);
+
+ mParams[0] = 0;
+ mParams[1] = partCount;
+ mParams[2] = 0;
+ mParams[3] = 0;
+ mParams[4] = 0;
+ mParams[5] = mPartAlloc.mID;
+ mParams[6] = mPF.mID;
+ mParams[7] = mPF2.mID;
+ mIntAlloc.data(mParams);
+
+ int t2[] = new int[partCount * 4*3];
+ for (int ct=0; ct < t2.length; ct++) {
+ t2[ct] = 0;
+ }
+ mPartAlloc.data(t2);
+
+ mRS.scriptCBegin();
+ mRS.scriptCSetClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ mRS.scriptCSetScript(getResources(), R.raw.fountain);
+ mRS.scriptCSetRoot(true);
+ mScript = mRS.scriptCCreate();
+
+ mScript.bindAllocation(mIntAlloc, 0);
+ mScript.bindAllocation(mPartAlloc, 1);
+ mScript.bindAllocation(mVertAlloc, 2);
+ mRS.contextBindRootScript(mScript);
+
+ }
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ super.surfaceChanged(holder, format, w, h);
+
+ initRS();
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event)
+ {
+ // break point at here
+ // this method doesn't work when 'extends View' include 'extends ScrollView'.
+ return super.onKeyDown(keyCode, event);
+ }
+
+ int mTouchAction;
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev)
+ {
+ //Log.e("FountainView", ev.toString());
+ boolean ret = true;
+ int act = ev.getAction();
+ mParams[1] = (int)ev.getX();
+ mParams[2] = (int)ev.getY();
+
+ if (act == ev.ACTION_DOWN) {
+ mParams[0] = 1;
+ } else if (act == ev.ACTION_UP) {
+ //mParams[0] = 0;
+ ret = false;
+ }
+ mIntAlloc.subData1D(2, 3, mParams);
+
+ return ret;
+ }
+}
+
+
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/RSSurfaceView.java b/libs/rs/java/Fountain/src/com/android/fountain/RSSurfaceView.java
new file mode 100644
index 0000000..a8b3bca
--- /dev/null
+++ b/libs/rs/java/Fountain/src/com/android/fountain/RSSurfaceView.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.fountain;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+public class RSSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
+ private SurfaceHolder mSurfaceHolder;
+
+ /**
+ * Standard View constructor. In order to render something, you
+ * must call {@link #setRenderer} to register a renderer.
+ */
+ public RSSurfaceView(Context context) {
+ super(context);
+ init();
+ Log.v("***", "RSSurfaceView");
+ }
+
+ /**
+ * Standard View constructor. In order to render something, you
+ * must call {@link #setRenderer} to register a renderer.
+ */
+ public RSSurfaceView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ Log.v("***", "RSSurfaceView");
+ }
+
+ private void init() {
+ // Install a SurfaceHolder.Callback so we get notified when the
+ // underlying surface is created and destroyed
+ SurfaceHolder holder = getHolder();
+ holder.addCallback(this);
+ holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
+ }
+
+ /**
+ * This method is part of the SurfaceHolder.Callback interface, and is
+ * not normally called or subclassed by clients of RSSurfaceView.
+ */
+ public void surfaceCreated(SurfaceHolder holder) {
+ Log.v("***", "surfaceCreated");
+ mSurfaceHolder = holder;
+ //mGLThread.surfaceCreated();
+ }
+
+ /**
+ * This method is part of the SurfaceHolder.Callback interface, and is
+ * not normally called or subclassed by clients of RSSurfaceView.
+ */
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ // Surface will be destroyed when we return
+ Log.v("***", "surfaceDestroyed");
+ //mGLThread.surfaceDestroyed();
+ }
+
+ /**
+ * This method is part of the SurfaceHolder.Callback interface, and is
+ * not normally called or subclassed by clients of RSSurfaceView.
+ */
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ Log.v("***", "surfaceChanged");
+
+ //mGLThread.onWindowResize(w, h);
+ }
+
+ /**
+ * Inform the view that the activity is paused. The owner of this view must
+ * call this method when the activity is paused. Calling this method will
+ * pause the rendering thread.
+ * Must not be called before a renderer has been set.
+ */
+ public void onPause() {
+ Log.v("***", "onPause");
+ //mGLThread.onPause();
+ }
+
+ /**
+ * Inform the view that the activity is resumed. The owner of this view must
+ * call this method when the activity is resumed. Calling this method will
+ * recreate the OpenGL display and resume the rendering
+ * thread.
+ * Must not be called before a renderer has been set.
+ */
+ public void onResume() {
+ Log.v("***", "onResume");
+ //mGLThread.onResume();
+ }
+
+ /**
+ * Queue a runnable to be run on the GL rendering thread. This can be used
+ * to communicate with the Renderer on the rendering thread.
+ * Must not be called before a renderer has been set.
+ * @param r the runnable to be run on the GL rendering thread.
+ */
+ public void queueEvent(Runnable r) {
+ Log.v("***", "queueEvent");
+ //mGLThread.queueEvent(r);
+ }
+
+ /**
+ * This method is used as part of the View class and is not normally
+ * called or subclassed by clients of RSSurfaceView.
+ * Must not be called before a renderer has been set.
+ */
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ //mGLThread.requestExitAndWait();
+ }
+
+ // ----------------------------------------------------------------------
+
+ public RenderScript createRenderScript() {
+ Log.v("***", "createRenderScript 1");
+ Surface sur = null;
+ while ((sur == null) || (mSurfaceHolder == null)) {
+ sur = getHolder().getSurface();
+ }
+ Log.v("***", "createRenderScript 2");
+ RenderScript rs = new RenderScript(sur);
+ Log.v("***", "createRenderScript 3 rs");
+ return rs;
+ }
+
+}
+
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/RenderScript.java b/libs/rs/java/Fountain/src/com/android/fountain/RenderScript.java
new file mode 100644
index 0000000..796fe35
--- /dev/null
+++ b/libs/rs/java/Fountain/src/com/android/fountain/RenderScript.java
@@ -0,0 +1,818 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.fountain;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+import android.os.Bundle;
+import android.content.res.Resources;
+import android.util.Log;
+import android.util.Config;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.Window;
+import android.view.View;
+import android.view.Surface;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+
+public class RenderScript {
+ private static final String LOG_TAG = "libRS_jni";
+ private static final boolean DEBUG = false;
+ private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
+
+
+
+ /*
+ * We use a class initializer to allow the native code to cache some
+ * field offsets.
+ */
+ private static boolean sInitialized;
+ native private static void _nInit();
+
+ static {
+ sInitialized = false;
+ try {
+ System.loadLibrary("RS_jni");
+ _nInit();
+ sInitialized = true;
+ } catch (UnsatisfiedLinkError e) {
+ Log.d(LOG_TAG, "RenderScript JNI library not found!");
+ }
+ }
+
+ native private int nDeviceCreate();
+ native private void nDeviceDestroy(int dev);
+ native private int nContextCreate(int dev, Surface sur, int ver);
+ native private void nContextDestroy(int con);
+
+ //void rsContextBindSampler (uint32_t slot, RsSampler sampler);
+ //void rsContextBindRootScript (RsScript sampler);
+ native private void nContextBindRootScript(int script);
+ native private void nContextBindSampler(int sampler, int slot);
+ native private void nContextBindProgramFragmentStore(int pfs);
+ native private void nContextBindProgramFragment(int pf);
+
+ native private void nElementBegin();
+ native private void nElementAddPredefined(int predef);
+ native private void nElementAdd(int kind, int type, int norm, int bits);
+ native private int nElementCreate();
+ native private int nElementGetPredefined(int predef);
+ native private void nElementDestroy(int obj);
+
+ native private void nTypeBegin(int elementID);
+ native private void nTypeAdd(int dim, int val);
+ native private int nTypeCreate();
+ native private void nTypeDestroy(int id);
+
+ native private int nAllocationCreateTyped(int type);
+ native private int nAllocationCreatePredefSized(int predef, int count);
+ native private int nAllocationCreateSized(int elem, int count);
+ native private int nAllocationCreateFromBitmap(int dstFmt, boolean genMips, Bitmap bmp);
+
+ native private void nAllocationUploadToTexture(int alloc, int baseMioLevel);
+ native private void nAllocationDestroy(int alloc);
+ native private void nAllocationData(int id, int[] d);
+ native private void nAllocationData(int id, float[] d);
+ native private void nAllocationSubData1D(int id, int off, int count, int[] d);
+ native private void nAllocationSubData1D(int id, int off, int count, float[] d);
+ native private void nAllocationSubData2D(int id, int xoff, int yoff, int w, int h, int[] d);
+ native private void nAllocationSubData2D(int id, int xoff, int yoff, int w, int h, float[] d);
+
+ native private void nTriangleMeshDestroy(int id);
+ native private void nTriangleMeshBegin(int vertex, int index);
+ native private void nTriangleMeshAddVertex_XY (float x, float y);
+ native private void nTriangleMeshAddVertex_XYZ (float x, float y, float z);
+ native private void nTriangleMeshAddVertex_XY_ST (float x, float y, float s, float t);
+ native private void nTriangleMeshAddVertex_XYZ_ST (float x, float y, float z, float s, float t);
+ native private void nTriangleMeshAddTriangle(int i1, int i2, int i3);
+ native private int nTriangleMeshCreate();
+
+ native private void nAdapter1DDestroy(int id);
+ native private void nAdapter1DBindAllocation(int ad, int alloc);
+ native private void nAdapter1DSetConstraint(int ad, int dim, int value);
+ native private void nAdapter1DData(int ad, int[] d);
+ native private void nAdapter1DSubData(int ad, int off, int count, int[] d);
+ native private void nAdapter1DData(int ad, float[] d);
+ native private void nAdapter1DSubData(int ad, int off, int count, float[] d);
+ native private int nAdapter1DCreate();
+
+ native private void nScriptDestroy(int script);
+ native private void nScriptBindAllocation(int vtm, int alloc, int slot);
+ native private void nScriptCBegin();
+ native private void nScriptCSetClearColor(float r, float g, float b, float a);
+ native private void nScriptCSetClearDepth(float depth);
+ native private void nScriptCSetClearStencil(int stencil);
+ native private void nScriptCAddType(int type);
+ native private void nScriptCSetRoot(boolean isRoot);
+ native private void nScriptCSetScript(byte[] script, int offset, int length);
+ native private int nScriptCCreate();
+
+ native private void nSamplerDestroy(int sampler);
+ native private void nSamplerBegin();
+ native private void nSamplerSet(int param, int value);
+ native private int nSamplerCreate();
+
+ native private void nProgramFragmentStoreBegin(int in, int out);
+ native private void nProgramFragmentStoreDepthFunc(int func);
+ native private void nProgramFragmentStoreDepthMask(boolean enable);
+ native private void nProgramFragmentStoreColorMask(boolean r, boolean g, boolean b, boolean a);
+ native private void nProgramFragmentStoreBlendFunc(int src, int dst);
+ native private void nProgramFragmentStoreDither(boolean enable);
+ native private int nProgramFragmentStoreCreate();
+
+ native private void nProgramFragmentBegin(int in, int out);
+ native private void nProgramFragmentBindTexture(int vpf, int slot, int a);
+ native private void nProgramFragmentBindSampler(int vpf, int slot, int s);
+ native private void nProgramFragmentSetType(int slot, int vt);
+ native private void nProgramFragmentSetEnvMode(int slot, int env);
+ native private void nProgramFragmentSetTexEnable(int slot, boolean enable);
+ native private int nProgramFragmentCreate();
+
+
+ private int mDev;
+ private int mContext;
+ private Surface mSurface;
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ //
+
+ RenderScript(Surface sur) {
+ mSurface = sur;
+ mDev = nDeviceCreate();
+ mContext = nContextCreate(mDev, mSurface, 0);
+ }
+
+ private class BaseObj {
+ BaseObj() {
+ mID = 0;
+ }
+
+ int mID;
+ protected void finalize() throws Throwable
+ {
+ if (mID != 0) {
+ Log.v(LOG_TAG,
+ "Element finalized without having released the RS reference.");
+ }
+ super.finalize();
+ }
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // Element
+
+ public enum ElementPredefined {
+ USER_U8 (0),
+ USER_I8 (1),
+ USER_U16 (2),
+ USER_I16 (3),
+ USER_U32 (4),
+ USER_I32 (5),
+ USER_FLOAT (6),
+
+ A_8 (7),
+ RGB_565 (8),
+ RGB_888 (12),
+ RGBA_5551 (9),
+ RGBA_4444 (10),
+ RGBA_8888 (13),
+
+ INDEX_16 (16),
+ INDEX_32 (17),
+ XY_F32 (18),
+ XYZ_F32 (19),
+ ST_XY_F32 (20),
+ ST_XYZ_F32 (21);
+
+ int mID;
+ ElementPredefined(int id) {
+ mID = id;
+ }
+ }
+
+ public enum DataType {
+ FLOAT (0),
+ UNSIGNED (1),
+ SIGNED (2);
+
+ int mID;
+ DataType(int id) {
+ mID = id;
+ }
+ }
+
+ public enum DataKind {
+ USER (0),
+ RED (1),
+ GREEN (2),
+ BLUE (3),
+ ALPHA (4),
+ LUMINANCE (5),
+ INTENSITY (6),
+ X (7),
+ Y (8),
+ Z (9),
+ W (10),
+ S (11),
+ T (12),
+ Q (13),
+ R (14),
+ NX (15),
+ NY (16),
+ NZ (17),
+ INDEX (18);
+
+ int mID;
+ DataKind(int id) {
+ mID = id;
+ }
+ }
+
+ public enum DepthFunc {
+ ALWAYS (0),
+ LESS (1),
+ LEQUAL (2),
+ GREATER (3),
+ GEQUAL (4),
+ EQUAL (5),
+ NOTEQUAL (6);
+
+ int mID;
+ DepthFunc(int id) {
+ mID = id;
+ }
+ }
+
+ public enum BlendSrcFunc {
+ ZERO (0),
+ ONE (1),
+ DST_COLOR (2),
+ ONE_MINUS_DST_COLOR (3),
+ SRC_ALPHA (4),
+ ONE_MINUS_SRC_ALPHA (5),
+ DST_ALPHA (6),
+ ONE_MINUS_DST_ALPA (7),
+ SRC_ALPHA_SATURATE (8);
+
+ int mID;
+ BlendSrcFunc(int id) {
+ mID = id;
+ }
+ }
+
+ public enum BlendDstFunc {
+ ZERO (0),
+ ONE (1),
+ SRC_COLOR (2),
+ ONE_MINUS_SRC_COLOR (3),
+ SRC_ALPHA (4),
+ ONE_MINUS_SRC_ALPHA (5),
+ DST_ALPHA (6),
+ ONE_MINUS_DST_ALPA (7);
+
+ int mID;
+ BlendDstFunc(int id) {
+ mID = id;
+ }
+ }
+
+ public enum EnvMode {
+ REPLACE (0),
+ MODULATE (1),
+ DECAL (2);
+
+ int mID;
+ EnvMode(int id) {
+ mID = id;
+ }
+ }
+
+ public enum SamplerParam {
+ FILTER_MIN (0),
+ FILTER_MAG (1),
+ WRAP_MODE_S (2),
+ WRAP_MODE_T (3),
+ WRAP_MODE_R (4);
+
+ int mID;
+ SamplerParam(int id) {
+ mID = id;
+ }
+ }
+
+ public enum SamplerValue {
+ NEAREST (0),
+ LINEAR (1),
+ LINEAR_MIP_LINEAR (2),
+ WRAP (3),
+ CLAMP (4);
+
+ int mID;
+ SamplerValue(int id) {
+ mID = id;
+ }
+ }
+
+
+
+ public class Element extends BaseObj {
+ Element(int id) {
+ mID = id;
+ }
+
+ public void estroy() {
+ nElementDestroy(mID);
+ mID = 0;
+ }
+ }
+
+ public void elementBegin() {
+ nElementBegin();
+ }
+
+ public void elementAddPredefined(ElementPredefined e) {
+ nElementAddPredefined(e.mID);
+ }
+
+ public void elementAdd(DataType dt, DataKind dk, boolean isNormalized, int bits) {
+ int norm = 0;
+ if (isNormalized) {
+ norm = 1;
+ }
+ nElementAdd(dt.mID, dk.mID, norm, bits);
+ }
+
+ public Element elementCreate() {
+ int id = nElementCreate();
+ return new Element(id);
+ }
+
+ public Element elementGetPredefined(ElementPredefined predef) {
+ int id = nElementGetPredefined(predef.mID);
+ return new Element(id);
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // Type
+
+ public enum Dimension {
+ X (0),
+ Y (1),
+ Z (2),
+ LOD (3),
+ FACE (4),
+ ARRAY_0 (100);
+
+ int mID;
+ Dimension(int id) {
+ mID = id;
+ }
+ }
+
+ public class Type extends BaseObj {
+ Type(int id) {
+ mID = id;
+ }
+
+ public void destroy() {
+ nTypeDestroy(mID);
+ mID = 0;
+ }
+ }
+
+ public void typeBegin(Element e) {
+ nTypeBegin(e.mID);
+ }
+
+ public void typeAdd(Dimension d, int value) {
+ nTypeAdd(d.mID, value);
+ }
+
+ public Type typeCreate() {
+ int id = nTypeCreate();
+ return new Type(id);
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // Allocation
+
+ public class Allocation extends BaseObj {
+ Allocation(int id) {
+ mID = id;
+ }
+
+ public void uploadToTexture(int baseMipLevel) {
+ nAllocationUploadToTexture(mID, baseMipLevel);
+ }
+
+ public void destroy() {
+ nAllocationDestroy(mID);
+ mID = 0;
+ }
+
+ public void data(int[] d) {
+ nAllocationData(mID, d);
+ }
+
+ public void data(float[] d) {
+ nAllocationData(mID, d);
+ }
+
+ public void subData1D(int off, int count, int[] d) {
+ nAllocationSubData1D(mID, off, count, d);
+ }
+
+ public void subData1D(int off, int count, float[] d) {
+ nAllocationSubData1D(mID, off, count, d);
+ }
+
+ public void subData2D(int xoff, int yoff, int w, int h, int[] d) {
+ nAllocationSubData2D(mID, xoff, yoff, w, h, d);
+ }
+
+ public void subData2D(int xoff, int yoff, int w, int h, float[] d) {
+ nAllocationSubData2D(mID, xoff, yoff, w, h, d);
+ }
+ }
+
+ public Allocation allocationCreateTyped(Type type) {
+ int id = nAllocationCreateTyped(type.mID);
+ return new Allocation(id);
+ }
+
+ public Allocation allocationCreatePredefSized(ElementPredefined e, int count) {
+ int id = nAllocationCreatePredefSized(e.mID, count);
+ return new Allocation(id);
+ }
+
+ public Allocation allocationCreateSized(Element e, int count) {
+ int id = nAllocationCreateSized(e.mID, count);
+ return new Allocation(id);
+ }
+
+ public Allocation allocationCreateFromBitmap(Bitmap b, ElementPredefined dstFmt, boolean genMips) {
+ int id = nAllocationCreateFromBitmap(dstFmt.mID, genMips, b);
+ return new Allocation(id);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // Adapter1D
+
+ public class Adapter1D extends BaseObj {
+ Adapter1D(int id) {
+ mID = id;
+ }
+
+ public void destroy() {
+ nAdapter1DDestroy(mID);
+ mID = 0;
+ }
+
+ public void bindAllocation(Allocation a) {
+ nAdapter1DBindAllocation(mID, a.mID);
+ }
+
+ public void setConstraint(Dimension dim, int value) {
+ nAdapter1DSetConstraint(mID, dim.mID, value);
+ }
+
+ public void data(int[] d) {
+ nAdapter1DData(mID, d);
+ }
+
+ public void subData(int off, int count, int[] d) {
+ nAdapter1DSubData(mID, off, count, d);
+ }
+
+ public void data(float[] d) {
+ nAdapter1DData(mID, d);
+ }
+
+ public void subData(int off, int count, float[] d) {
+ nAdapter1DSubData(mID, off, count, d);
+ }
+ }
+
+ public Adapter1D adapter1DCreate() {
+ int id = nAdapter1DCreate();
+ return new Adapter1D(id);
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // Triangle Mesh
+
+ public class TriangleMesh extends BaseObj {
+ TriangleMesh(int id) {
+ mID = id;
+ }
+
+ public void destroy() {
+ nTriangleMeshDestroy(mID);
+ mID = 0;
+ }
+ }
+
+ public void triangleMeshBegin(Element vertex, Element index) {
+ nTriangleMeshBegin(vertex.mID, index.mID);
+ }
+
+ public void triangleMeshAddVertex_XY(float x, float y) {
+ nTriangleMeshAddVertex_XY(x, y);
+ }
+
+ public void triangleMeshAddVertex_XYZ(float x, float y, float z) {
+ nTriangleMeshAddVertex_XYZ(x, y, z);
+ }
+
+ public void triangleMeshAddVertex_XY_ST(float x, float y, float s, float t) {
+ nTriangleMeshAddVertex_XY_ST(x, y, s, t);
+ }
+
+ public void triangleMeshAddVertex_XYZ_ST(float x, float y, float z, float s, float t) {
+ nTriangleMeshAddVertex_XYZ_ST(x, y, z, s, t);
+ }
+
+ public void triangleMeshAddTriangle(int i1, int i2, int i3) {
+ nTriangleMeshAddTriangle(i1, i2, i3);
+ }
+
+ public TriangleMesh triangleMeshCreate() {
+ int id = nTriangleMeshCreate();
+ return new TriangleMesh(id);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // Script
+
+ public class Script extends BaseObj {
+ Script(int id) {
+ mID = id;
+ }
+
+ public void destroy() {
+ nScriptDestroy(mID);
+ mID = 0;
+ }
+
+ public void bindAllocation(Allocation va, int slot) {
+ nScriptBindAllocation(mID, va.mID, slot);
+ }
+ }
+
+ public void scriptCBegin() {
+ nScriptCBegin();
+ }
+
+ public void scriptCSetClearColor(float r, float g, float b, float a) {
+ nScriptCSetClearColor(r, g, b, a);
+ }
+
+ public void scriptCSetClearDepth(float d) {
+ nScriptCSetClearDepth(d);
+ }
+
+ public void scriptCSetClearStencil(int stencil) {
+ nScriptCSetClearStencil(stencil);
+ }
+
+ public void scriptCAddType(Type t) {
+ nScriptCAddType(t.mID);
+ }
+
+ public void scriptCSetRoot(boolean r) {
+ nScriptCSetRoot(r);
+ }
+
+ public void scriptCSetScript(String s) {
+ try {
+ byte[] bytes = s.getBytes("UTF-8");
+ nScriptCSetScript(bytes, 0, bytes.length);
+ } catch (java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void scriptCSetScript(Resources resources, int id) {
+ InputStream is = resources.openRawResource(id);
+ try {
+ try {
+ scriptCSetScript(is);
+ } finally {
+ is.close();
+ }
+ } catch(IOException e) {
+ throw new Resources.NotFoundException();
+ }
+ }
+
+ public void scriptCSetScript(InputStream is) throws IOException {
+ byte[] buf = new byte[1024];
+ int currentPos = 0;
+ while(true) {
+ int bytesLeft = buf.length - currentPos;
+ if (bytesLeft == 0) {
+ byte[] buf2 = new byte[buf.length * 2];
+ System.arraycopy(buf, 0, buf2, 0, buf.length);
+ buf = buf2;
+ bytesLeft = buf.length - currentPos;
+ }
+ int bytesRead = is.read(buf, currentPos, bytesLeft);
+ if (bytesRead <= 0) {
+ break;
+ }
+ currentPos += bytesRead;
+ }
+ nScriptCSetScript(buf, 0, currentPos);
+ }
+
+ public Script scriptCCreate() {
+ int id = nScriptCCreate();
+ return new Script(id);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // ProgramFragmentStore
+
+ public class ProgramFragmentStore extends BaseObj {
+ ProgramFragmentStore(int id) {
+ mID = id;
+ }
+
+ public void destroy() {
+ nScriptDestroy(mID);
+ mID = 0;
+ }
+ }
+
+ public void programFragmentStoreBegin(Element in, Element out) {
+ int inID = 0;
+ int outID = 0;
+ if (in != null) {
+ inID = in.mID;
+ }
+ if (out != null) {
+ outID = out.mID;
+ }
+ nProgramFragmentStoreBegin(inID, outID);
+ }
+
+ public void programFragmentStoreDepthFunc(DepthFunc func) {
+ nProgramFragmentStoreDepthFunc(func.mID);
+ }
+
+ public void programFragmentStoreDepthMask(boolean enable) {
+ nProgramFragmentStoreDepthMask(enable);
+ }
+
+ public void programFragmentStoreColorMask(boolean r, boolean g, boolean b, boolean a) {
+ nProgramFragmentStoreColorMask(r,g,b,a);
+ }
+
+ public void programFragmentStoreBlendFunc(BlendSrcFunc src, BlendDstFunc dst) {
+ nProgramFragmentStoreBlendFunc(src.mID, dst.mID);
+ }
+
+ public void programFragmentStoreDitherEnable(boolean enable) {
+ nProgramFragmentStoreDither(enable);
+ }
+
+ public ProgramFragmentStore programFragmentStoreCreate() {
+ int id = nProgramFragmentStoreCreate();
+ return new ProgramFragmentStore(id);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // ProgramFragment
+
+ public class ProgramFragment extends BaseObj {
+ ProgramFragment(int id) {
+ mID = id;
+ }
+
+ public void destroy() {
+ nScriptDestroy(mID);
+ mID = 0;
+ }
+
+ public void bindTexture(Allocation va, int slot) {
+ nProgramFragmentBindTexture(mID, slot, va.mID);
+ }
+
+ public void bindSampler(Sampler vs, int slot) {
+ nProgramFragmentBindSampler(mID, slot, vs.mID);
+ }
+ }
+
+ public void programFragmentBegin(Element in, Element out) {
+ int inID = 0;
+ int outID = 0;
+ if (in != null) {
+ inID = in.mID;
+ }
+ if (out != null) {
+ outID = out.mID;
+ }
+ nProgramFragmentBegin(inID, outID);
+ }
+
+ public void programFragmentSetType(int slot, Type t) {
+ nProgramFragmentSetType(slot, t.mID);
+ }
+
+ public void programFragmentSetType(int slot, EnvMode t) {
+ nProgramFragmentSetEnvMode(slot, t.mID);
+ }
+
+ public void programFragmentSetTexEnable(int slot, boolean enable) {
+ nProgramFragmentSetTexEnable(slot, enable);
+ }
+
+ public ProgramFragment programFragmentCreate() {
+ int id = nProgramFragmentCreate();
+ return new ProgramFragment(id);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // Sampler
+
+ public class Sampler extends BaseObj {
+ Sampler(int id) {
+ mID = id;
+ }
+
+ public void destroy() {
+ nSamplerDestroy(mID);
+ mID = 0;
+ }
+ }
+
+ public void samplerBegin() {
+ nSamplerBegin();
+ }
+
+ public void samplerSet(SamplerParam p, SamplerValue v) {
+ nSamplerSet(p.mID, v.mID);
+ }
+
+ public Sampler samplerCreate() {
+ int id = nSamplerCreate();
+ return new Sampler(id);
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ // Root state
+
+ public void contextBindRootScript(Script s) {
+ nContextBindRootScript(s.mID);
+ }
+
+ //public void contextBindSampler(Sampler s, int slot) {
+ //nContextBindSampler(s.mID);
+ //}
+
+ public void contextBindProgramFragmentStore(ProgramFragmentStore pfs) {
+ nContextBindProgramFragmentStore(pfs.mID);
+ }
+
+ public void contextBindProgramFragment(ProgramFragment pf) {
+ nContextBindProgramFragment(pf.mID);
+ }
+
+/*
+ RsAdapter2D rsAdapter2DCreate ();
+ void rsAdapter2DBindAllocation (RsAdapter2D adapt, RsAllocation alloc);
+ void rsAdapter2DDestroy (RsAdapter2D adapter);
+ void rsAdapter2DSetConstraint (RsAdapter2D adapter, RsDimension dim, uint32_t value);
+ void rsAdapter2DData (RsAdapter2D adapter, const void * data);
+ void rsAdapter2DSubData (RsAdapter2D adapter, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void * data);
+ void rsSamplerBegin ();
+ void rsSamplerSet (RsSamplerParam p, RsSamplerValue value);
+ RsSampler rsSamplerCreate ();
+ void rsSamplerBind (RsSampler sampler, RsAllocation alloc);
+*/
+
+}
+
diff --git a/libs/rs/jni/RenderScript_jni.cpp b/libs/rs/jni/RenderScript_jni.cpp
new file mode 100644
index 0000000..677ce0c
--- /dev/null
+++ b/libs/rs/jni/RenderScript_jni.cpp
@@ -0,0 +1,912 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <math.h>
+
+#include <utils/misc.h>
+#include <utils/Log.h>
+
+#include <ui/EGLNativeWindowSurface.h>
+#include <ui/Surface.h>
+
+#include <core/SkBitmap.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include "../RenderScript.h"
+#include "../RenderScriptEnv.h"
+
+//#define LOG_API LOGE
+#define LOG_API(...)
+
+using namespace android;
+
+// ---------------------------------------------------------------------------
+
+static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
+{
+ jclass npeClazz = env->FindClass(exc);
+ env->ThrowNew(npeClazz, msg);
+}
+
+static jfieldID gContextId = 0;
+static jfieldID gNativeBitmapID = 0;
+
+static void _nInit(JNIEnv *_env, jclass _this)
+{
+ gContextId = _env->GetFieldID(_this, "mContext", "I");
+
+ jclass bitmapClass = _env->FindClass("android/graphics/Bitmap");
+ gNativeBitmapID = _env->GetFieldID(bitmapClass, "mNativeBitmap", "I");
+}
+
+
+// ---------------------------------------------------------------------------
+
+static jint
+nDeviceCreate(JNIEnv *_env, jobject _this)
+{
+ LOG_API("nDeviceCreate");
+ return (jint)rsDeviceCreate();
+}
+
+static void
+nDeviceDestroy(JNIEnv *_env, jobject _this, jint dev)
+{
+ LOG_API("nDeviceDestroy");
+ return rsDeviceDestroy((RsDevice)dev);
+}
+
+static jint
+nContextCreate(JNIEnv *_env, jobject _this, jint dev, jobject wnd, jint ver)
+{
+ LOG_API("nContextCreate");
+
+ if (wnd == NULL) {
+ not_valid_surface:
+ doThrow(_env, "java/lang/IllegalArgumentException",
+ "Make sure the SurfaceView or associated SurfaceHolder has a valid Surface");
+ return 0;
+ }
+ jclass surface_class = _env->FindClass("android/view/Surface");
+ jfieldID surfaceFieldID = _env->GetFieldID(surface_class, "mSurface", "I");
+ Surface * window = (Surface*)_env->GetIntField(wnd, surfaceFieldID);
+ if (window == NULL)
+ goto not_valid_surface;
+
+ LOGE("nContextCreate 5");
+ return (jint)rsContextCreate((RsDevice)dev, window, ver);
+}
+
+static void
+nContextDestroy(JNIEnv *_env, jobject _this, jint con)
+{
+ LOG_API("nContextDestroy, con(%p)", (RsContext)con);
+ return rsContextDestroy((RsContext)con);
+}
+
+
+static void
+nElementBegin(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nElementBegin, con(%p)", con);
+ rsElementBegin();
+}
+
+static void
+nElementAddPredefined(JNIEnv *_env, jobject _this, jint predef)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nElementAddPredefined, con(%p), predef(%i)", con, predef);
+ rsElementAddPredefined((RsElementPredefined)predef);
+}
+
+static void
+nElementAdd(JNIEnv *_env, jobject _this, jint kind, jint type, jint norm, jint bits)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nElementAdd, con(%p), kind(%i), type(%i), norm(%i), bits(%i)", con, kind, type, norm, bits);
+ rsElementAdd((RsDataKind)kind, (RsDataType)type, norm != 0, (size_t)bits);
+}
+
+static jint
+nElementCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nElementCreate, con(%p)", con);
+ return (jint)rsElementCreate();
+}
+
+static jint
+nElementGetPredefined(JNIEnv *_env, jobject _this, jint predef)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nElementGetPredefined, con(%p) predef(%i)", con, predef);
+ return (jint)rsElementGetPredefined((RsElementPredefined)predef);
+}
+
+static void
+nElementDestroy(JNIEnv *_env, jobject _this, jint e)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nElementDestroy, con(%p) e(%p)", con, (RsElement)e);
+ rsElementDestroy((RsElement)e);
+}
+
+// -----------------------------------
+
+static void
+nTypeBegin(JNIEnv *_env, jobject _this, jint eID)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nTypeBegin, con(%p) e(%p)", con, (RsElement)eID);
+ rsTypeBegin((RsElement)eID);
+}
+
+static void
+nTypeAdd(JNIEnv *_env, jobject _this, jint dim, jint val)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nTypeAdd, con(%p) dim(%i), val(%i)", con, dim, val);
+ rsTypeAdd((RsDimension)dim, val);
+}
+
+static jint
+nTypeCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nTypeCreate, con(%p)", con);
+ return (jint)rsTypeCreate();
+}
+
+static void
+nTypeDestroy(JNIEnv *_env, jobject _this, jint eID)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nTypeDestroy, con(%p), t(%p)", con, (RsType)eID);
+ rsTypeDestroy((RsType)eID);
+}
+
+// -----------------------------------
+
+static jint
+nAllocationCreateTyped(JNIEnv *_env, jobject _this, jint e)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAllocationCreateTyped, con(%p), e(%p)", con, (RsElement)e);
+ return (jint) rsAllocationCreateTyped((RsElement)e);
+}
+
+static jint
+nAllocationCreatePredefSized(JNIEnv *_env, jobject _this, jint predef, jint count)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAllocationCreatePredefSized, con(%p), predef(%i), count(%i)", con, predef, count);
+ return (jint) rsAllocationCreatePredefSized((RsElementPredefined)predef, count);
+}
+
+static jint
+nAllocationCreateSized(JNIEnv *_env, jobject _this, jint e, jint count)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAllocationCreateSized, con(%p), e(%p), count(%i)", con, (RsElement)e, count);
+ return (jint) rsAllocationCreateSized((RsElement)e, count);
+}
+
+static void
+nAllocationUploadToTexture(JNIEnv *_env, jobject _this, jint a, jint mip)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAllocationUploadToTexture, con(%p), a(%p), mip(%i)", con, (RsAllocation)a, mip);
+ rsAllocationUploadToTexture((RsAllocation)a, mip);
+}
+
+static RsElementPredefined SkBitmapToPredefined(SkBitmap::Config cfg)
+{
+ switch (cfg) {
+ case SkBitmap::kA8_Config:
+ return RS_ELEMENT_A_8;
+ case SkBitmap::kARGB_4444_Config:
+ return RS_ELEMENT_RGBA_4444;
+ case SkBitmap::kARGB_8888_Config:
+ return RS_ELEMENT_RGBA_8888;
+ case SkBitmap::kRGB_565_Config:
+ return RS_ELEMENT_RGB_565;
+
+ default:
+ break;
+ }
+ // If we don't have a conversion mark it as a user type.
+ LOGE("Unsupported bitmap type");
+ return RS_ELEMENT_USER_U8;
+}
+
+static int
+nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, jint dstFmt, jboolean genMips, jobject jbitmap)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ SkBitmap const * nativeBitmap =
+ (SkBitmap const *)_env->GetIntField(jbitmap, gNativeBitmapID);
+ const SkBitmap& bitmap(*nativeBitmap);
+ SkBitmap::Config config = bitmap.getConfig();
+
+ RsElementPredefined e = SkBitmapToPredefined(config);
+
+ if (e != RS_ELEMENT_USER_U8) {
+ bitmap.lockPixels();
+ const int w = bitmap.width();
+ const int h = bitmap.height();
+ const void* ptr = bitmap.getPixels();
+ jint id = (jint)rsAllocationCreateFromBitmap(w, h, (RsElementPredefined)dstFmt, e, genMips, ptr);
+ bitmap.unlockPixels();
+ return id;
+ }
+ return 0;
+}
+
+
+static void
+nAllocationDestroy(JNIEnv *_env, jobject _this, jint a)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAllocationDestroy, con(%p), a(%p)", con, (RsAllocation)a);
+ rsAllocationDestroy((RsAllocation)a);
+}
+
+static void
+nAllocationData_i(JNIEnv *_env, jobject _this, jint alloc, jintArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(data);
+ LOG_API("nAllocationData_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
+ jint *ptr = _env->GetIntArrayElements(data, NULL);
+ rsAllocationData((RsAllocation)alloc, ptr);
+ _env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationData_f(JNIEnv *_env, jobject _this, jint alloc, jfloatArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(data);
+ LOG_API("nAllocationData_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
+ jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
+ rsAllocationData((RsAllocation)alloc, ptr);
+ _env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationSubData1D_i(JNIEnv *_env, jobject _this, jint alloc, jint offset, jint count, jintArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(data);
+ LOG_API("nAllocation1DSubData_i, con(%p), adapter(%p), offset(%i), count(%i), len(%i)", con, (RsAllocation)alloc, offset, count, len);
+ jint *ptr = _env->GetIntArrayElements(data, NULL);
+ rsAllocation1DSubData((RsAllocation)alloc, offset, count, ptr);
+ _env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationSubData1D_f(JNIEnv *_env, jobject _this, jint alloc, jint offset, jint count, jfloatArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(data);
+ LOG_API("nAllocation1DSubData_f, con(%p), adapter(%p), offset(%i), count(%i), len(%i)", con, (RsAllocation)alloc, offset, count, len);
+ jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
+ rsAllocation1DSubData((RsAllocation)alloc, offset, count, ptr);
+ _env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationSubData2D_i(JNIEnv *_env, jobject _this, jint alloc, jint xoff, jint yoff, jint w, jint h, jintArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(data);
+ LOG_API("nAllocation2DSubData_i, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, w, h, len);
+ jint *ptr = _env->GetIntArrayElements(data, NULL);
+ rsAllocation2DSubData((RsAllocation)alloc, xoff, yoff, w, h, ptr);
+ _env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationSubData2D_f(JNIEnv *_env, jobject _this, jint alloc, jint xoff, jint yoff, jint w, jint h, jfloatArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(data);
+ LOG_API("nAllocation2DSubData_i, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, w, h, len);
+ jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
+ rsAllocation2DSubData((RsAllocation)alloc, xoff, yoff, w, h, ptr);
+ _env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT);
+}
+
+
+
+// -----------------------------------
+
+static void
+nTriangleMeshDestroy(JNIEnv *_env, jobject _this, jint tm)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nTriangleMeshDestroy, con(%p), tm(%p)", con, (RsAllocation)tm);
+ rsTriangleMeshDestroy((RsTriangleMesh)tm);
+}
+
+static void
+nTriangleMeshBegin(JNIEnv *_env, jobject _this, jint v, jint i)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nTriangleMeshBegin, con(%p), vertex(%p), index(%p)", con, (RsElement)v, (RsElement)i);
+ rsTriangleMeshBegin((RsElement)v, (RsElement)i);
+}
+
+static void
+nTriangleMeshAddVertex_XY(JNIEnv *_env, jobject _this, jfloat x, jfloat y)
+{
+ float v[] = {x, y};
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nTriangleMeshAddVertex_XY, con(%p), x(%f), y(%f)", con, x, y);
+ rsTriangleMeshAddVertex(v);
+}
+
+static void
+nTriangleMeshAddVertex_XYZ(JNIEnv *_env, jobject _this, jfloat x, jfloat y, jfloat z)
+{
+ float v[] = {x, y, z};
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nTriangleMeshAddVertex_XYZ, con(%p), x(%f), y(%f), z(%f)", con, x, y, z);
+ rsTriangleMeshAddVertex(v);
+}
+
+static void
+nTriangleMeshAddVertex_XY_ST(JNIEnv *_env, jobject _this, jfloat x, jfloat y, jfloat s, jfloat t)
+{
+ float v[] = {s, t, x, y};
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nTriangleMeshAddVertex_XY_ST, con(%p), x(%f), y(%f), s(%f), t(%f)", con, x, y, s, t);
+ rsTriangleMeshAddVertex(v);
+}
+
+static void
+nTriangleMeshAddVertex_XYZ_ST(JNIEnv *_env, jobject _this, jfloat x, jfloat y, jfloat z, jfloat s, jfloat t)
+{
+ float v[] = {s, t, x, y, z};
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nTriangleMeshAddVertex_XYZ_ST, con(%p), x(%f), y(%f), z(%f), s(%f), t(%f)", con, x, y, z, s, t);
+ rsTriangleMeshAddVertex(v);
+}
+
+static void
+nTriangleMeshAddTriangle(JNIEnv *_env, jobject _this, jint i1, jint i2, jint i3)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nTriangleMeshAddTriangle, con(%p), i1(%i), i2(%i), i3(%i)", con, i1, i2, i3);
+ rsTriangleMeshAddTriangle(i1, i2, i3);
+}
+
+static jint
+nTriangleMeshCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nTriangleMeshCreate, con(%p)", con);
+ return (jint) rsTriangleMeshCreate();
+}
+
+// -----------------------------------
+
+static void
+nAdapter1DDestroy(JNIEnv *_env, jobject _this, jint adapter)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAdapter1DDestroy, con(%p), adapter(%p)", con, (RsAdapter1D)adapter);
+ rsAdapter1DDestroy((RsAdapter1D)adapter);
+}
+
+static void
+nAdapter1DBindAllocation(JNIEnv *_env, jobject _this, jint adapter, jint alloc)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAdapter1DBindAllocation, con(%p), adapter(%p), alloc(%p)", con, (RsAdapter1D)adapter, (RsAllocation)alloc);
+ rsAdapter1DBindAllocation((RsAdapter1D)adapter, (RsAllocation)alloc);
+}
+
+static void
+nAdapter1DSetConstraint(JNIEnv *_env, jobject _this, jint adapter, jint dim, jint value)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAdapter1DSetConstraint, con(%p), adapter(%p), dim(%i), value(%i)", con, (RsAdapter1D)adapter, dim, value);
+ rsAdapter1DSetConstraint((RsAdapter1D)adapter, (RsDimension)dim, value);
+}
+
+static void
+nAdapter1DData_i(JNIEnv *_env, jobject _this, jint adapter, jintArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(data);
+ LOG_API("nAdapter1DData_i, con(%p), adapter(%p), len(%i)", con, (RsAdapter1D)adapter, len);
+ jint *ptr = _env->GetIntArrayElements(data, NULL);
+ rsAdapter1DData((RsAdapter1D)adapter, ptr);
+ _env->ReleaseIntArrayElements(data, ptr, 0/*JNI_ABORT*/);
+}
+
+static void
+nAdapter1DSubData_i(JNIEnv *_env, jobject _this, jint adapter, jint offset, jint count, jintArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(data);
+ LOG_API("nAdapter1DSubData_i, con(%p), adapter(%p), offset(%i), count(%i), len(%i)", con, (RsAdapter1D)adapter, offset, count, len);
+ jint *ptr = _env->GetIntArrayElements(data, NULL);
+ rsAdapter1DSubData((RsAdapter1D)adapter, offset, count, ptr);
+ _env->ReleaseIntArrayElements(data, ptr, 0/*JNI_ABORT*/);
+}
+
+static void
+nAdapter1DData_f(JNIEnv *_env, jobject _this, jint adapter, jfloatArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(data);
+ LOG_API("nAdapter1DData_f, con(%p), adapter(%p), len(%i)", con, (RsAdapter1D)adapter, len);
+ jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
+ rsAdapter1DData((RsAdapter1D)adapter, ptr);
+ _env->ReleaseFloatArrayElements(data, ptr, 0/*JNI_ABORT*/);
+}
+
+static void
+nAdapter1DSubData_f(JNIEnv *_env, jobject _this, jint adapter, jint offset, jint count, jfloatArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(data);
+ LOG_API("nAdapter1DSubData_f, con(%p), adapter(%p), offset(%i), count(%i), len(%i)", con, (RsAdapter1D)adapter, offset, count, len);
+ jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
+ rsAdapter1DSubData((RsAdapter1D)adapter, offset, count, ptr);
+ _env->ReleaseFloatArrayElements(data, ptr, 0/*JNI_ABORT*/);
+}
+
+static jint
+nAdapter1DCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAdapter1DCreate, con(%p)", con);
+ return (jint)rsAdapter1DCreate();
+}
+
+// -----------------------------------
+
+static void
+nScriptDestroy(JNIEnv *_env, jobject _this, jint script)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptDestroy, con(%p), script(%p)", con, (RsScript)script);
+ rsScriptDestroy((RsScript)script);
+}
+
+static void
+nScriptBindAllocation(JNIEnv *_env, jobject _this, jint script, jint alloc, jint slot)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptBindAllocation, con(%p), script(%p), alloc(%p), slot(%i)", con, (RsScript)script, (RsAllocation)alloc, slot);
+ rsScriptBindAllocation((RsScript)script, (RsAllocation)alloc, slot);
+}
+
+static void
+nScriptCBegin(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptCBegin, con(%p)", con);
+ rsScriptCBegin();
+}
+
+static void
+nScriptCSetClearColor(JNIEnv *_env, jobject _this, jfloat r, jfloat g, jfloat b, jfloat a)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptCSetClearColor, con(%p), r(%f), g(%f), b(%f), a(%f)", con, r, g, b, a);
+ rsScriptCSetClearColor(r, g, b, a);
+}
+
+static void
+nScriptCSetClearDepth(JNIEnv *_env, jobject _this, jfloat d)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptCSetClearColor, con(%p), depth(%f)", con, d);
+ rsScriptCSetClearDepth(d);
+}
+
+static void
+nScriptCSetClearStencil(JNIEnv *_env, jobject _this, jint stencil)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptCSetClearStencil, con(%p), stencil(%i)", con, stencil);
+ rsScriptCSetClearStencil(stencil);
+}
+
+static void
+nScriptCAddType(JNIEnv *_env, jobject _this, jint type)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptCAddType, con(%p), type(%p)", con, (RsType)type);
+ rsScriptCAddType((RsType)type);
+}
+
+static void
+nScriptCSetRoot(JNIEnv *_env, jobject _this, jboolean isRoot)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptCSetRoot, con(%p), isRoot(%i)", con, isRoot);
+ rsScriptCSetRoot(isRoot);
+}
+
+static void
+nScriptCSetScript(JNIEnv *_env, jobject _this, jbyteArray scriptRef,
+ jint offset, jint length)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("!!! nScriptCSetScript, con(%p)", con);
+ jint _exception = 0;
+ jint remaining;
+ jbyte* script_base = 0;
+ jbyte* script_ptr;
+ if (!scriptRef) {
+ _exception = 1;
+ //_env->ThrowNew(IAEClass, "script == null");
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ //_env->ThrowNew(IAEClass, "offset < 0");
+ goto exit;
+ }
+ if (length < 0) {
+ _exception = 1;
+ //_env->ThrowNew(IAEClass, "length < 0");
+ goto exit;
+ }
+ remaining = _env->GetArrayLength(scriptRef) - offset;
+ if (remaining < length) {
+ _exception = 1;
+ //_env->ThrowNew(IAEClass, "length > script.length - offset");
+ goto exit;
+ }
+ script_base = (jbyte *)
+ _env->GetPrimitiveArrayCritical(scriptRef, (jboolean *)0);
+ script_ptr = script_base + offset;
+
+ rsScriptCSetText((const char *)script_ptr, length);
+
+exit:
+ if (script_base) {
+ _env->ReleasePrimitiveArrayCritical(scriptRef, script_base,
+ _exception ? JNI_ABORT: 0);
+ }
+}
+
+static jint
+nScriptCCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptCCreate, con(%p)", con);
+ return (jint)rsScriptCCreate();
+}
+
+// ---------------------------------------------------------------------------
+
+static void
+nProgramFragmentStoreBegin(JNIEnv *_env, jobject _this, jint in, jint out)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentStoreBegin, con(%p), in(%p), out(%p)", con, (RsElement)in, (RsElement)out);
+ rsProgramFragmentStoreBegin((RsElement)in, (RsElement)out);
+}
+
+static void
+nProgramFragmentStoreDepthFunc(JNIEnv *_env, jobject _this, jint func)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentStoreDepthFunc, con(%p), func(%i)", con, func);
+ rsProgramFragmentStoreDepthFunc((RsDepthFunc)func);
+}
+
+static void
+nProgramFragmentStoreDepthMask(JNIEnv *_env, jobject _this, jboolean enable)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentStoreDepthMask, con(%p), enable(%i)", con, enable);
+ rsProgramFragmentStoreDepthMask(enable);
+}
+
+static void
+nProgramFragmentStoreColorMask(JNIEnv *_env, jobject _this, jboolean r, jboolean g, jboolean b, jboolean a)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentStoreColorMask, con(%p), r(%i), g(%i), b(%i), a(%i)", con, r, g, b, a);
+ rsProgramFragmentStoreColorMask(r, g, b, a);
+}
+
+static void
+nProgramFragmentStoreBlendFunc(JNIEnv *_env, jobject _this, int src, int dst)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentStoreBlendFunc, con(%p), src(%i), dst(%i)", con, src, dst);
+ rsProgramFragmentStoreBlendFunc((RsBlendSrcFunc)src, (RsBlendDstFunc)dst);
+}
+
+static void
+nProgramFragmentStoreDither(JNIEnv *_env, jobject _this, jboolean enable)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentStoreDither, con(%p), enable(%i)", con, enable);
+ rsProgramFragmentStoreDither(enable);
+}
+
+static jint
+nProgramFragmentStoreCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentStoreCreate, con(%p)", con);
+ return (jint)rsProgramFragmentStoreCreate();
+}
+
+// ---------------------------------------------------------------------------
+
+static void
+nProgramFragmentBegin(JNIEnv *_env, jobject _this, jint in, jint out)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentBegin, con(%p), in(%p), out(%p)", con, (RsElement)in, (RsElement)out);
+ rsProgramFragmentBegin((RsElement)in, (RsElement)out);
+}
+
+static void
+nProgramFragmentBindTexture(JNIEnv *_env, jobject _this, jint vpf, jint slot, jint a)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentBindTexture, con(%p), vpf(%p), slot(%i), a(%p)", con, (RsProgramFragment)vpf, slot, (RsAllocation)a);
+ rsProgramFragmentBindTexture((RsProgramFragment)vpf, slot, (RsAllocation)a);
+}
+
+static void
+nProgramFragmentBindSampler(JNIEnv *_env, jobject _this, jint vpf, jint slot, jint a)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentBindSampler, con(%p), vpf(%p), slot(%i), a(%p)", con, (RsProgramFragment)vpf, slot, (RsSampler)a);
+ rsProgramFragmentBindSampler((RsProgramFragment)vpf, slot, (RsSampler)a);
+}
+
+static void
+nProgramFragmentSetType(JNIEnv *_env, jobject _this, jint slot, jint vt)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentSetType, con(%p), slot(%i), vt(%p)", con, slot, (RsType)vt);
+ rsProgramFragmentSetType(slot, (RsType)vt);
+}
+
+static void
+nProgramFragmentSetEnvMode(JNIEnv *_env, jobject _this, jint slot, jint env)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentSetEnvMode, con(%p), slot(%i), vt(%i)", con, slot, env);
+ rsProgramFragmentSetEnvMode(slot, (RsTexEnvMode)env);
+}
+
+static void
+nProgramFragmentSetTexEnable(JNIEnv *_env, jobject _this, jint slot, jboolean enable)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentSetTexEnable, con(%p), slot(%i), enable(%i)", con, slot, enable);
+ rsProgramFragmentSetTexEnable(slot, enable);
+}
+
+static jint
+nProgramFragmentCreate(JNIEnv *_env, jobject _this, jint slot, jboolean enable)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentCreate, con(%p)", con);
+ return (jint)rsProgramFragmentCreate();
+}
+
+
+// ---------------------------------------------------------------------------
+
+static void
+nContextBindRootScript(JNIEnv *_env, jobject _this, jint script)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nContextBindRootScript, con(%p), script(%p)", con, (RsScript)script);
+ rsContextBindRootScript((RsScript)script);
+}
+
+static void
+nContextBindProgramFragmentStore(JNIEnv *_env, jobject _this, jint pfs)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nContextBindProgramFragmentStore, con(%p), pfs(%p)", con, (RsProgramFragmentStore)pfs);
+ rsContextBindProgramFragmentStore((RsProgramFragmentStore)pfs);
+}
+
+static void
+nContextBindProgramFragment(JNIEnv *_env, jobject _this, jint pf)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nContextBindProgramFragment, con(%p), pf(%p)", con, (RsProgramFragment)pf);
+ rsContextBindProgramFragment((RsProgramFragment)pf);
+}
+
+// ---------------------------------------------------------------------------
+
+static void
+nSamplerDestroy(JNIEnv *_env, jobject _this, jint s)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nSamplerDestroy, con(%p), sampler(%p)", con, (RsSampler)s);
+ rsSamplerDestroy((RsSampler)s);
+}
+
+static void
+nSamplerBegin(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nSamplerBegin, con(%p)", con);
+ rsSamplerBegin();
+}
+
+static void
+nSamplerSet(JNIEnv *_env, jobject _this, jint p, jint v)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nSamplerSet, con(%p), param(%i), value(%i)", con, p, v);
+ rsSamplerSet((RsSamplerParam)p, (RsSamplerValue)v);
+}
+
+static jint
+nSamplerCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nSamplerCreate, con(%p), script(%p)", con, (RsScript)script);
+ return (jint)rsSamplerCreate();
+}
+
+
+// ---------------------------------------------------------------------------
+
+
+static const char *classPathName = "com/android/fountain/RenderScript";
+
+static JNINativeMethod methods[] = {
+{"_nInit", "()V", (void*)_nInit },
+{"nDeviceCreate", "()I", (void*)nDeviceCreate },
+{"nDeviceDestroy", "(I)V", (void*)nDeviceDestroy },
+{"nContextCreate", "(ILandroid/view/Surface;I)I", (void*)nContextCreate },
+{"nContextDestroy", "(I)V", (void*)nContextDestroy },
+
+{"nElementBegin", "()V", (void*)nElementBegin },
+{"nElementAddPredefined", "(I)V", (void*)nElementAddPredefined },
+{"nElementAdd", "(IIII)V", (void*)nElementAdd },
+{"nElementCreate", "()I", (void*)nElementCreate },
+{"nElementGetPredefined", "(I)I", (void*)nElementGetPredefined },
+{"nElementDestroy", "(I)V", (void*)nElementDestroy },
+
+{"nTypeBegin", "(I)V", (void*)nTypeBegin },
+{"nTypeAdd", "(II)V", (void*)nTypeAdd },
+{"nTypeCreate", "()I", (void*)nTypeCreate },
+{"nTypeDestroy", "(I)V", (void*)nTypeDestroy },
+
+{"nAllocationCreateTyped", "(I)I", (void*)nAllocationCreateTyped },
+{"nAllocationCreatePredefSized", "(II)I", (void*)nAllocationCreatePredefSized },
+{"nAllocationCreateSized", "(II)I", (void*)nAllocationCreateSized },
+{"nAllocationCreateFromBitmap", "(IZLandroid/graphics/Bitmap;)I", (void*)nAllocationCreateFromBitmap },
+{"nAllocationUploadToTexture", "(II)V", (void*)nAllocationUploadToTexture },
+{"nAllocationDestroy", "(I)V", (void*)nAllocationDestroy },
+{"nAllocationData", "(I[I)V", (void*)nAllocationData_i },
+{"nAllocationData", "(I[F)V", (void*)nAllocationData_f },
+{"nAllocationSubData1D", "(III[I)V", (void*)nAllocationSubData1D_i },
+{"nAllocationSubData1D", "(III[F)V", (void*)nAllocationSubData1D_f },
+{"nAllocationSubData2D", "(IIIII[I)V", (void*)nAllocationSubData2D_i },
+{"nAllocationSubData2D", "(IIIII[F)V", (void*)nAllocationSubData2D_f },
+
+{"nTriangleMeshDestroy", "(I)V", (void*)nTriangleMeshDestroy },
+{"nTriangleMeshBegin", "(II)V", (void*)nTriangleMeshBegin },
+{"nTriangleMeshAddVertex_XY", "(FF)V", (void*)nTriangleMeshAddVertex_XY },
+{"nTriangleMeshAddVertex_XYZ", "(FFF)V", (void*)nTriangleMeshAddVertex_XYZ },
+{"nTriangleMeshAddVertex_XY_ST", "(FFFF)V", (void*)nTriangleMeshAddVertex_XY_ST },
+{"nTriangleMeshAddVertex_XYZ_ST", "(FFFFF)V", (void*)nTriangleMeshAddVertex_XYZ_ST },
+{"nTriangleMeshAddTriangle", "(III)V", (void*)nTriangleMeshAddTriangle },
+{"nTriangleMeshCreate", "()I", (void*)nTriangleMeshCreate },
+
+{"nAdapter1DDestroy", "(I)V", (void*)nAdapter1DDestroy },
+{"nAdapter1DBindAllocation", "(II)V", (void*)nAdapter1DBindAllocation },
+{"nAdapter1DSetConstraint", "(III)V", (void*)nAdapter1DSetConstraint },
+{"nAdapter1DData", "(I[I)V", (void*)nAdapter1DData_i },
+{"nAdapter1DSubData", "(III[I)V", (void*)nAdapter1DSubData_i },
+{"nAdapter1DData", "(I[F)V", (void*)nAdapter1DData_f },
+{"nAdapter1DSubData", "(III[F)V", (void*)nAdapter1DSubData_f },
+{"nAdapter1DCreate", "()I", (void*)nAdapter1DCreate },
+
+{"nScriptDestroy", "(I)V", (void*)nScriptDestroy },
+{"nScriptBindAllocation", "(III)V", (void*)nScriptBindAllocation },
+{"nScriptCBegin", "()V", (void*)nScriptCBegin },
+{"nScriptCSetClearColor", "(FFFF)V", (void*)nScriptCSetClearColor },
+{"nScriptCSetClearDepth", "(F)V", (void*)nScriptCSetClearDepth },
+{"nScriptCSetClearStencil", "(I)V", (void*)nScriptCSetClearStencil },
+{"nScriptCAddType", "(I)V", (void*)nScriptCAddType },
+{"nScriptCSetRoot", "(Z)V", (void*)nScriptCSetRoot },
+{"nScriptCSetScript", "([BII)V", (void*)nScriptCSetScript },
+{"nScriptCCreate", "()I", (void*)nScriptCCreate },
+
+{"nProgramFragmentStoreBegin", "(II)V", (void*)nProgramFragmentStoreBegin },
+{"nProgramFragmentStoreDepthFunc", "(I)V", (void*)nProgramFragmentStoreDepthFunc },
+{"nProgramFragmentStoreDepthMask", "(Z)V", (void*)nProgramFragmentStoreDepthMask },
+{"nProgramFragmentStoreColorMask", "(ZZZZ)V", (void*)nProgramFragmentStoreColorMask },
+{"nProgramFragmentStoreBlendFunc", "(II)V", (void*)nProgramFragmentStoreBlendFunc },
+{"nProgramFragmentStoreDither", "(Z)V", (void*)nProgramFragmentStoreDither },
+{"nProgramFragmentStoreCreate", "()I", (void*)nProgramFragmentStoreCreate },
+
+{"nProgramFragmentBegin", "(II)V", (void*)nProgramFragmentBegin },
+{"nProgramFragmentBindTexture", "(III)V", (void*)nProgramFragmentBindTexture },
+{"nProgramFragmentBindSampler", "(III)V", (void*)nProgramFragmentBindSampler },
+{"nProgramFragmentSetType", "(II)V", (void*)nProgramFragmentSetType },
+{"nProgramFragmentSetEnvMode", "(II)V", (void*)nProgramFragmentSetEnvMode },
+{"nProgramFragmentSetTexEnable", "(IZ)V", (void*)nProgramFragmentSetTexEnable },
+{"nProgramFragmentCreate", "()I", (void*)nProgramFragmentCreate },
+
+{"nContextBindRootScript", "(I)V", (void*)nContextBindRootScript },
+{"nContextBindProgramFragmentStore","(I)V", (void*)nContextBindProgramFragmentStore },
+{"nContextBindProgramFragment", "(I)V", (void*)nContextBindProgramFragment },
+
+{"nSamplerDestroy", "(I)V", (void*)nSamplerDestroy },
+{"nSamplerBegin", "()V", (void*)nSamplerBegin },
+{"nSamplerSet", "(II)V", (void*)nSamplerSet },
+{"nSamplerCreate", "()I", (void*)nSamplerCreate },
+
+};
+
+static int registerFuncs(JNIEnv *_env)
+{
+ return android::AndroidRuntime::registerNativeMethods(
+ _env, classPathName, methods, NELEM(methods));
+}
+
+// ---------------------------------------------------------------------------
+
+jint JNI_OnLoad(JavaVM* vm, void* reserved)
+{
+ JNIEnv* env = NULL;
+ jint result = -1;
+
+ LOGE("****************************************************\n");
+
+ if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+ LOGE("ERROR: GetEnv failed\n");
+ goto bail;
+ }
+ assert(env != NULL);
+
+ if (registerFuncs(env) < 0) {
+ LOGE("ERROR: MediaPlayer native registration failed\n");
+ goto bail;
+ }
+
+ /* success -- return valid version number */
+ result = JNI_VERSION_1_4;
+
+bail:
+ return result;
+}
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
new file mode 100644
index 0000000..4ffdfce
--- /dev/null
+++ b/libs/rs/rs.spec
@@ -0,0 +1,406 @@
+
+
+ContextBindRootScript {
+ param RsScript sampler
+ }
+
+ContextBindProgramFragmentStore {
+ param RsProgramFragmentStore pgm
+ }
+
+ContextBindProgramFragment {
+ param RsProgramFragment pgm
+ }
+
+ContextBindProgramVertex {
+ param RsProgramVertex pgm
+ }
+
+
+ElementBegin {
+}
+
+ElementAddPredefined {
+ param RsElementPredefined predef
+ }
+
+ElementAdd {
+ param RsDataKind dataKind
+ param RsDataType dataType
+ param bool isNormalized
+ param size_t bits
+ }
+
+ElementCreate {
+ ret RsElement
+ }
+
+ElementGetPredefined {
+ param RsElementPredefined predef
+ ret RsElement
+ }
+
+ElementDestroy {
+ param RsElement ve
+ }
+
+TypeBegin {
+ param RsElement type
+ }
+
+TypeAdd {
+ param RsDimension dim
+ param size_t value
+ }
+
+TypeCreate {
+ ret RsType
+ }
+
+TypeDestroy {
+ param RsType p
+ }
+
+AllocationCreateTyped {
+ param RsType type
+ ret RsAllocation
+ }
+
+AllocationCreatePredefSized {
+ param RsElementPredefined predef
+ param size_t count
+ ret RsAllocation
+ }
+
+AllocationCreateSized {
+ param RsElement e
+ param size_t count
+ ret RsAllocation
+ }
+
+AllocationCreateFromFile {
+ param const char *file
+ param bool genMips
+ ret RsAllocation
+ }
+
+AllocationCreateFromBitmap {
+ param uint32_t width
+ param uint32_t height
+ param RsElementPredefined dstFmt
+ param RsElementPredefined srcFmt
+ param bool genMips
+ param const void * data
+ ret RsAllocation
+ }
+
+
+AllocationUploadToTexture {
+ param RsAllocation alloc
+ param uint32_t baseMipLevel
+ }
+
+AllocationUploadToBufferObject {
+ param RsAllocation alloc
+ }
+
+AllocationDestroy {
+ param RsAllocation alloc
+ }
+
+
+AllocationData {
+ param RsAllocation va
+ param const void * data
+ }
+
+Allocation1DSubData {
+ param RsAllocation va
+ param uint32_t xoff
+ param uint32_t count
+ param const void *data
+ }
+
+Allocation2DSubData {
+ param RsAllocation va
+ param uint32_t xoff
+ param uint32_t yoff
+ param uint32_t w
+ param uint32_t h
+ param const void *data
+ }
+
+
+Adapter1DCreate {
+ ret RsAdapter1D
+ }
+
+Adapter1DBindAllocation {
+ param RsAdapter1D adapt
+ param RsAllocation alloc
+ }
+
+Adapter1DDestroy {
+ param RsAdapter1D adapter
+ }
+
+Adapter1DSetConstraint {
+ param RsAdapter1D adapter
+ param RsDimension dim
+ param uint32_t value
+ }
+
+Adapter1DData {
+ param RsAdapter1D adapter
+ param const void * data
+ }
+
+Adapter1DSubData {
+ param RsAdapter1D adapter
+ param uint32_t xoff
+ param uint32_t count
+ param const void *data
+ }
+
+Adapter2DCreate {
+ ret RsAdapter2D
+ }
+
+Adapter2DBindAllocation {
+ param RsAdapter2D adapt
+ param RsAllocation alloc
+ }
+
+Adapter2DDestroy {
+ param RsAdapter2D adapter
+ }
+
+Adapter2DSetConstraint {
+ param RsAdapter2D adapter
+ param RsDimension dim
+ param uint32_t value
+ }
+
+Adapter2DData {
+ param RsAdapter2D adapter
+ param const void *data
+ }
+
+Adapter2DSubData {
+ param RsAdapter2D adapter
+ param uint32_t xoff
+ param uint32_t yoff
+ param uint32_t w
+ param uint32_t h
+ param const void *data
+ }
+
+SamplerBegin {
+ }
+
+SamplerSet {
+ param RsSamplerParam p
+ param RsSamplerValue value
+ }
+
+SamplerCreate {
+ ret RsSampler
+ }
+
+SamplerDestroy {
+ param RsSampler s
+ }
+
+TriangleMeshBegin {
+ param RsElement vertex
+ param RsElement index
+ }
+
+TriangleMeshAddVertex {
+ param const void *vtx
+ }
+
+TriangleMeshAddTriangle {
+ param uint32_t idx1
+ param uint32_t idx2
+ param uint32_t idx3
+ }
+
+TriangleMeshCreate {
+ ret RsTriangleMesh
+ }
+
+TriangleMeshDestroy {
+ param RsTriangleMesh mesh
+ }
+
+TriangleMeshRender {
+ param RsTriangleMesh vtm
+ }
+
+TriangleMeshRenderRange {
+ param RsTriangleMesh vtm
+ param uint32_t start
+ param uint32_t count
+ }
+
+ScriptDestroy {
+ param RsScript script
+ }
+
+ScriptBindAllocation {
+ param RsScript vtm
+ param RsAllocation va
+ param uint32_t slot
+ }
+
+
+ScriptCBegin {
+ }
+
+ScriptCSetClearColor {
+ param float r
+ param float g
+ param float b
+ param float a
+ }
+
+ScriptCSetClearDepth {
+ param float depth
+ }
+
+ScriptCSetClearStencil {
+ param uint32_t stencil
+ }
+
+ScriptCAddType {
+ param RsType type
+ }
+
+ScriptCSetRoot {
+ param bool isRoot
+ }
+
+ScriptCSetOrtho {
+ param bool isOrtho
+ }
+
+ScriptCSetScript {
+ param void * codePtr
+ }
+
+ScriptCSetText {
+ param const char * text
+ param uint32_t length
+ }
+
+ScriptCCreate {
+ ret RsScript
+ }
+
+
+ProgramFragmentStoreBegin {
+ param RsElement in
+ param RsElement out
+ }
+
+ProgramFragmentStoreColorMask {
+ param bool r
+ param bool g
+ param bool b
+ param bool a
+ }
+
+ProgramFragmentStoreBlendFunc {
+ param RsBlendSrcFunc srcFunc
+ param RsBlendDstFunc destFunc
+ }
+
+ProgramFragmentStoreDepthMask {
+ param bool enable
+}
+
+ProgramFragmentStoreDither {
+ param bool enable
+}
+
+ProgramFragmentStoreDepthFunc {
+ param RsDepthFunc func
+}
+
+ProgramFragmentStoreCreate {
+ ret RsProgramFragmentStore
+ }
+
+
+
+ProgramFragmentBegin {
+ param RsElement in
+ param RsElement out
+ }
+
+ProgramFragmentBindTexture {
+ param RsProgramFragment pf
+ param uint32_t slot
+ param RsAllocation a
+ }
+
+ProgramFragmentBindSampler {
+ param RsProgramFragment pf
+ param uint32_t slot
+ param RsSampler s
+ }
+
+ProgramFragmentSetType {
+ param uint32_t slot
+ param RsType t
+ }
+
+ProgramFragmentSetEnvMode {
+ param uint32_t slot
+ param RsTexEnvMode env
+ }
+
+ProgramFragmentSetTexEnable {
+ param uint32_t slot
+ param bool enable
+ }
+
+ProgramFragmentCreate {
+ ret RsProgramFragment
+ }
+
+
+
+ProgramVertexBegin {
+ param RsElement in
+ param RsElement out
+ }
+
+ProgramVertexCreate {
+ ret RsProgramVertex
+ }
+
+ProgramVertexBindAllocation {
+ param RsProgramVertex vpgm
+ param uint32_t slot
+ param RsAllocation constants
+ }
+
+ProgramVertexSetType {
+ param uint32_t slot
+ param RsType constants
+ }
+
+ProgramVertexSetCameraMode {
+ param bool ortho
+ }
+
+ProgramVertexSetTextureMatrixEnable {
+ param bool enable
+ }
+
+ProgramVertexSetModelMatrixEnable {
+ param bool enable
+ }
+
diff --git a/libs/rs/rsAdapter.cpp b/libs/rs/rsAdapter.cpp
new file mode 100644
index 0000000..7ac2aed
--- /dev/null
+++ b/libs/rs/rsAdapter.cpp
@@ -0,0 +1,245 @@
+
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Adapter1D::Adapter1D()
+{
+ reset();
+}
+
+Adapter1D::Adapter1D(Allocation *a)
+{
+ reset();
+ setAllocation(a);
+}
+
+void Adapter1D::reset()
+{
+ mY = 0;
+ mZ = 0;
+ mLOD = 0;
+ mFace = 0;
+}
+
+void * Adapter1D::getElement(uint32_t x)
+{
+ rsAssert(mAllocation.get());
+ rsAssert(mAllocation->getPtr());
+ rsAssert(mAllocation->getType());
+ uint8_t * ptr = static_cast<uint8_t *>(mAllocation->getPtr());
+ ptr += mAllocation->getType()->getLODOffset(mLOD, x, mY);
+ return ptr;
+}
+
+void Adapter1D::subData(uint32_t xoff, uint32_t count, const void *data)
+{
+ if (mAllocation.get() && mAllocation.get()->getType()) {
+ void *ptr = getElement(xoff);
+ count *= mAllocation.get()->getType()->getElementSizeBytes();
+ memcpy(ptr, data, count);
+ }
+}
+
+void Adapter1D::data(const void *data)
+{
+ memcpy(getElement(0),
+ data,
+ mAllocation.get()->getType()->getSizeBytes());
+}
+
+namespace android {
+namespace renderscript {
+
+RsAdapter1D rsi_Adapter1DCreate(Context *rsc)
+{
+ return new Adapter1D();
+}
+
+void rsi_Adapter1DDestroy(Context *rsc, RsAdapter1D va)
+{
+ Adapter1D * a = static_cast<Adapter1D *>(va);
+ a->decRef();
+}
+
+void rsi_Adapter1DBindAllocation(Context *rsc, RsAdapter1D va, RsAllocation valloc)
+{
+ Adapter1D * a = static_cast<Adapter1D *>(va);
+ Allocation * alloc = static_cast<Allocation *>(valloc);
+ a->setAllocation(alloc);
+}
+
+void rsi_Adapter1DSetConstraint(Context *rsc, RsAdapter1D va, RsDimension dim, uint32_t value)
+{
+ Adapter1D * a = static_cast<Adapter1D *>(va);
+ switch(dim) {
+ case RS_DIMENSION_X:
+ rsAssert(!"Cannot contrain X in an 1D adapter");
+ return;
+ case RS_DIMENSION_Y:
+ a->setY(value);
+ break;
+ case RS_DIMENSION_Z:
+ a->setZ(value);
+ break;
+ case RS_DIMENSION_LOD:
+ a->setLOD(value);
+ break;
+ case RS_DIMENSION_FACE:
+ a->setFace(value);
+ break;
+ default:
+ rsAssert(!"Unimplemented constraint");
+ return;
+ }
+}
+
+void rsi_Adapter1DSubData(Context *rsc, RsAdapter1D va, uint32_t xoff, uint32_t count, const void *data)
+{
+ Adapter1D * a = static_cast<Adapter1D *>(va);
+ a->subData(xoff, count, data);
+}
+
+void rsi_Adapter1DData(Context *rsc, RsAdapter1D va, const void *data)
+{
+ Adapter1D * a = static_cast<Adapter1D *>(va);
+ a->data(data);
+}
+
+}
+}
+
+//////////////////////////
+
+Adapter2D::Adapter2D()
+{
+ reset();
+}
+
+Adapter2D::Adapter2D(Allocation *a)
+{
+ reset();
+ setAllocation(a);
+}
+
+void Adapter2D::reset()
+{
+ mZ = 0;
+ mLOD = 0;
+ mFace = 0;
+}
+
+void * Adapter2D::getElement(uint32_t x, uint32_t y) const
+{
+ rsAssert(mAllocation.get());
+ rsAssert(mAllocation->getPtr());
+ rsAssert(mAllocation->getType());
+ uint8_t * ptr = static_cast<uint8_t *>(mAllocation->getPtr());
+ ptr += mAllocation->getType()->getLODOffset(mLOD, x, y);
+ return ptr;
+}
+
+void Adapter2D::subData(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data)
+{
+ rsAssert(mAllocation.get());
+ rsAssert(mAllocation->getPtr());
+ rsAssert(mAllocation->getType());
+
+ uint32_t eSize = mAllocation.get()->getType()->getElementSizeBytes();
+ uint32_t lineSize = eSize * w;
+ uint32_t destW = getDimX();
+
+ const uint8_t *src = static_cast<const uint8_t *>(data);
+ for (uint32_t line=yoff; line < (yoff+h); line++) {
+ memcpy(getElement(xoff, line), src, lineSize);
+ src += lineSize;
+ }
+}
+
+void Adapter2D::data(const void *data)
+{
+ memcpy(getElement(0,0),
+ data,
+ mAllocation.get()->getType()->getSizeBytes());
+}
+
+
+
+namespace android {
+namespace renderscript {
+
+RsAdapter2D rsi_Adapter2DCreate(Context *rsc)
+{
+ return new Adapter2D();
+}
+
+void rsi_Adapter2DDestroy(Context *rsc, RsAdapter2D va)
+{
+ Adapter2D * a = static_cast<Adapter2D *>(va);
+ a->decRef();
+}
+
+void rsi_Adapter2DBindAllocation(Context *rsc, RsAdapter2D va, RsAllocation valloc)
+{
+ Adapter2D * a = static_cast<Adapter2D *>(va);
+ Allocation * alloc = static_cast<Allocation *>(valloc);
+ a->setAllocation(alloc);
+}
+
+void rsi_Adapter2DSetConstraint(Context *rsc, RsAdapter2D va, RsDimension dim, uint32_t value)
+{
+ Adapter2D * a = static_cast<Adapter2D *>(va);
+ switch(dim) {
+ case RS_DIMENSION_X:
+ rsAssert(!"Cannot contrain X in an 2D adapter");
+ return;
+ case RS_DIMENSION_Y:
+ rsAssert(!"Cannot contrain Y in an 2D adapter");
+ break;
+ case RS_DIMENSION_Z:
+ a->setZ(value);
+ break;
+ case RS_DIMENSION_LOD:
+ a->setLOD(value);
+ break;
+ case RS_DIMENSION_FACE:
+ a->setFace(value);
+ break;
+ default:
+ rsAssert(!"Unimplemented constraint");
+ return;
+ }
+}
+
+void rsi_Adapter2DData(Context *rsc, RsAdapter2D va, const void *data)
+{
+ Adapter2D * a = static_cast<Adapter2D *>(va);
+ a->data(data);
+}
+
+void rsi_Adapter2DSubData(Context *rsc, RsAdapter2D va, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data)
+{
+ Adapter2D * a = static_cast<Adapter2D *>(va);
+ a->subData(xoff, yoff, w, h, data);
+}
+
+}
+}
diff --git a/libs/rs/rsAdapter.h b/libs/rs/rsAdapter.h
new file mode 100644
index 0000000..865535e
--- /dev/null
+++ b/libs/rs/rsAdapter.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_ADAPTER_H
+#define ANDROID_RS_ADAPTER_H
+
+#include "rsAllocation.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+class Adapter1D : public ObjectBase
+{
+
+public:
+ // By policy this allocation will hold a pointer to the type
+ // but will not destroy it on destruction.
+ Adapter1D();
+ Adapter1D(Allocation *);
+ void reset();
+ void * getElement(uint32_t x);
+
+ void setAllocation(Allocation *a) {mAllocation.set(a);}
+
+ uint32_t getDimX() const {return mAllocation->getType()->getLODDimX(mLOD);}
+
+ const Type * getBaseType() const {return mAllocation->getType();}
+
+ inline void setY(uint32_t y) {mY = y;}
+ inline void setZ(uint32_t z) {mZ = z;}
+ inline void setLOD(uint32_t lod) {mLOD = lod;}
+ inline void setFace(uint32_t face) {mFace = face;}
+ //void setArray(uint32_t num, uint32_t value);
+
+ void subData(uint32_t xoff, uint32_t count, const void *data);
+ void data(const void *data);
+
+protected:
+ ObjectBaseRef<Allocation> mAllocation;
+ uint32_t mY;
+ uint32_t mZ;
+ uint32_t mLOD;
+ uint32_t mFace;
+};
+
+class Adapter2D : public ObjectBase
+{
+
+public:
+ // By policy this allocation will hold a pointer to the type
+ // but will not destroy it on destruction.
+ Adapter2D();
+ Adapter2D(Allocation *);
+ void reset();
+ void * getElement(uint32_t x, uint32_t y) const;
+
+ uint32_t getDimX() const {return mAllocation->getType()->getLODDimX(mLOD);}
+ uint32_t getDimY() const {return mAllocation->getType()->getLODDimY(mLOD);}
+ const Type * getBaseType() const {return mAllocation->getType();}
+
+ void setAllocation(Allocation *a) {mAllocation.set(a);}
+ inline void setZ(uint32_t z) {mZ = z;}
+ inline void setLOD(uint32_t lod) {mLOD = lod;}
+ inline void setFace(uint32_t face) {mFace = face;}
+ //void setArray(uint32_t num, uint32_t value);
+
+ void data(const void *data);
+ void subData(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data);
+
+protected:
+ ObjectBaseRef<Allocation> mAllocation;
+ uint32_t mZ;
+ uint32_t mLOD;
+ uint32_t mFace;
+};
+
+
+}
+}
+#endif
+
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
new file mode 100644
index 0000000..3a01a75
--- /dev/null
+++ b/libs/rs/rsAllocation.cpp
@@ -0,0 +1,478 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+Allocation::Allocation(const Type *type)
+{
+ mPtr = NULL;
+
+ mCpuWrite = false;
+ mCpuRead = false;
+ mGpuWrite = false;
+ mGpuRead = false;
+
+ mReadWriteRatio = 0;
+ mUpdateSize = 0;
+
+ mIsTexture = false;
+ mTextureID = 0;
+
+ mIsVertexBuffer = false;
+ mBufferID = 0;
+
+ mType.set(type);
+ mPtr = malloc(mType->getSizeBytes());
+ if (!mPtr) {
+ LOGE("Allocation::Allocation, alloc failure");
+ }
+
+}
+
+Allocation::~Allocation()
+{
+ LOGE("Allocation %p destryed", this);
+}
+
+void Allocation::setCpuWritable(bool)
+{
+}
+
+void Allocation::setGpuWritable(bool)
+{
+}
+
+void Allocation::setCpuReadable(bool)
+{
+}
+
+void Allocation::setGpuReadable(bool)
+{
+}
+
+bool Allocation::fixAllocation()
+{
+ return false;
+}
+
+void Allocation::uploadToTexture(uint32_t lodOffset)
+{
+ //rsAssert(!mTextureId);
+ rsAssert(lodOffset < mType->getLODCount());
+
+ //LOGE("uploadToTexture %i, lod %i", mTextureID, lodOffset);
+
+ GLenum type = mType->getElement()->getGLType();
+ GLenum format = mType->getElement()->getGLFormat();
+
+ if (!type || !format) {
+ return;
+ }
+
+ if (!mTextureID) {
+ glGenTextures(1, &mTextureID);
+ }
+ glBindTexture(GL_TEXTURE_2D, mTextureID);
+
+ Adapter2D adapt(this);
+ for(uint32_t lod = 0; (lod + lodOffset) < mType->getLODCount(); lod++) {
+ adapt.setLOD(lod+lodOffset);
+
+ uint16_t * ptr = static_cast<uint16_t *>(adapt.getElement(0,0));
+ glTexImage2D(GL_TEXTURE_2D, lod, format,
+ adapt.getDimX(), adapt.getDimY(),
+ 0, format, type, ptr);
+ }
+}
+
+void Allocation::uploadToBufferObject()
+{
+ rsAssert(!mType->getDimY());
+ rsAssert(!mType->getDimZ());
+
+ //LOGE("uploadToTexture %i, lod %i", mTextureID, lodOffset);
+
+ if (!mBufferID) {
+ glGenBuffers(1, &mBufferID);
+ }
+ glBindBuffer(GL_ARRAY_BUFFER, mBufferID);
+ glBufferData(GL_ARRAY_BUFFER, mType->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+void Allocation::data(const void *data)
+{
+ memcpy(mPtr, data, mType->getSizeBytes());
+}
+
+void Allocation::subData(uint32_t xoff, uint32_t count, const void *data)
+{
+ uint32_t eSize = mType->getElementSizeBytes();
+ uint8_t * ptr = static_cast<uint8_t *>(mPtr);
+ ptr += eSize * xoff;
+ memcpy(ptr, data, count * eSize);
+}
+
+void Allocation::subData(uint32_t xoff, uint32_t yoff,
+ uint32_t w, uint32_t h, const void *data)
+{
+ uint32_t eSize = mType->getElementSizeBytes();
+ uint32_t lineSize = eSize * w;
+ uint32_t destW = mType->getDimX();
+
+ const uint8_t *src = static_cast<const uint8_t *>(data);
+ uint8_t *dst = static_cast<uint8_t *>(mPtr);
+ dst += eSize * (xoff + yoff * destW);
+ for (uint32_t line=yoff; line < (yoff+h); line++) {
+ uint8_t * ptr = static_cast<uint8_t *>(mPtr);
+ memcpy(dst, src, lineSize);
+ src += lineSize;
+ dst += destW * eSize;
+ }
+}
+
+void Allocation::subData(uint32_t xoff, uint32_t yoff, uint32_t zoff,
+ uint32_t w, uint32_t h, uint32_t d, const void *data)
+{
+}
+
+
+
+/////////////////
+//
+
+
+namespace android {
+namespace renderscript {
+
+RsAllocation rsi_AllocationCreateTyped(Context *rsc, RsType vtype)
+{
+ const Type * type = static_cast<const Type *>(vtype);
+
+ Allocation * alloc = new Allocation(type);
+ return alloc;
+}
+
+RsAllocation rsi_AllocationCreatePredefSized(Context *rsc, RsElementPredefined t, size_t count)
+{
+ RsElement e = rsi_ElementGetPredefined(rsc, t);
+ return rsi_AllocationCreateSized(rsc, e, count);
+}
+
+RsAllocation rsi_AllocationCreateSized(Context *rsc, RsElement e, size_t count)
+{
+ Type * type = new Type();
+ type->setDimX(count);
+ type->setElement(static_cast<Element *>(e));
+ type->compute();
+ return rsi_AllocationCreateTyped(rsc, type);
+}
+
+void rsi_AllocationUploadToTexture(Context *rsc, RsAllocation va, uint32_t baseMipLevel)
+{
+ Allocation *alloc = static_cast<Allocation *>(va);
+ alloc->uploadToTexture(baseMipLevel);
+}
+
+void rsi_AllocationUploadToBufferObject(Context *rsc, RsAllocation va)
+{
+ Allocation *alloc = static_cast<Allocation *>(va);
+ alloc->uploadToBufferObject();
+}
+
+void rsi_AllocationDestroy(Context *rsc, RsAllocation)
+{
+}
+
+static void mip565(const Adapter2D &out, const Adapter2D &in)
+{
+ uint32_t w = out.getDimX();
+ uint32_t h = out.getDimY();
+
+ for (uint32_t y=0; y < w; y++) {
+ uint16_t *oPtr = static_cast<uint16_t *>(out.getElement(0, y));
+ const uint16_t *i1 = static_cast<uint16_t *>(in.getElement(0, y*2));
+ const uint16_t *i2 = static_cast<uint16_t *>(in.getElement(0, y*2+1));
+
+ for (uint32_t x=0; x < h; x++) {
+ *oPtr = rsBoxFilter565(i1[0], i1[1], i2[0], i2[1]);
+ oPtr ++;
+ i1 += 2;
+ i2 += 2;
+ }
+ }
+}
+
+static void mip8888(const Adapter2D &out, const Adapter2D &in)
+{
+ uint32_t w = out.getDimX();
+ uint32_t h = out.getDimY();
+
+ for (uint32_t y=0; y < w; y++) {
+ uint32_t *oPtr = static_cast<uint32_t *>(out.getElement(0, y));
+ const uint32_t *i1 = static_cast<uint32_t *>(in.getElement(0, y*2));
+ const uint32_t *i2 = static_cast<uint32_t *>(in.getElement(0, y*2+1));
+
+ for (uint32_t x=0; x < h; x++) {
+ *oPtr = rsBoxFilter8888(i1[0], i1[1], i2[0], i2[1]);
+ oPtr ++;
+ i1 += 2;
+ i2 += 2;
+ }
+ }
+
+}
+
+
+typedef void (*ElementConverter_t)(void *dst, const void *src, uint32_t count);
+
+static void elementConverter_cpy_16(void *dst, const void *src, uint32_t count)
+{
+ memcpy(dst, src, count * 2);
+}
+static void elementConverter_cpy_8(void *dst, const void *src, uint32_t count)
+{
+ memcpy(dst, src, count);
+}
+static void elementConverter_cpy_32(void *dst, const void *src, uint32_t count)
+{
+ memcpy(dst, src, count * 4);
+}
+
+
+static void elementConverter_888_to_565(void *dst, const void *src, uint32_t count)
+{
+ uint16_t *d = static_cast<uint16_t *>(dst);
+ const uint8_t *s = static_cast<const uint8_t *>(src);
+
+ while(count--) {
+ *d = rs888to565(s[0], s[1], s[2]);
+ d++;
+ s+= 3;
+ }
+}
+
+static void elementConverter_8888_to_565(void *dst, const void *src, uint32_t count)
+{
+ uint16_t *d = static_cast<uint16_t *>(dst);
+ const uint8_t *s = static_cast<const uint8_t *>(src);
+
+ while(count--) {
+ *d = rs888to565(s[0], s[1], s[2]);
+ d++;
+ s+= 4;
+ }
+}
+
+static ElementConverter_t pickConverter(RsElementPredefined dstFmt, RsElementPredefined srcFmt)
+{
+ if ((dstFmt == RS_ELEMENT_RGB_565) &&
+ (srcFmt == RS_ELEMENT_RGB_565)) {
+ return elementConverter_cpy_16;
+ }
+
+ if ((dstFmt == RS_ELEMENT_RGB_565) &&
+ (srcFmt == RS_ELEMENT_RGB_888)) {
+ return elementConverter_888_to_565;
+ }
+
+ if ((dstFmt == RS_ELEMENT_RGB_565) &&
+ (srcFmt == RS_ELEMENT_RGBA_8888)) {
+ return elementConverter_8888_to_565;
+ }
+
+ if ((dstFmt == RS_ELEMENT_RGBA_8888) &&
+ (srcFmt == RS_ELEMENT_RGBA_8888)) {
+ return elementConverter_cpy_32;
+ }
+
+ LOGE("pickConverter, unsuported combo");
+ return 0;
+}
+
+
+RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, uint32_t w, uint32_t h, RsElementPredefined dstFmt, RsElementPredefined srcFmt, bool genMips, const void *data)
+{
+ rsi_TypeBegin(rsc, rsi_ElementGetPredefined(rsc, RS_ELEMENT_RGB_565));
+ rsi_TypeAdd(rsc, RS_DIMENSION_X, w);
+ rsi_TypeAdd(rsc, RS_DIMENSION_Y, h);
+ if (genMips) {
+ rsi_TypeAdd(rsc, RS_DIMENSION_LOD, 1);
+ }
+ RsType type = rsi_TypeCreate(rsc);
+
+ RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, type);
+ Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
+ if (texAlloc == NULL) {
+ LOGE("Memory allocation failure");
+ return NULL;
+ }
+ texAlloc->incRef();
+
+ ElementConverter_t cvt = pickConverter(dstFmt, srcFmt);
+ cvt(texAlloc->getPtr(), data, w * h);
+
+ if (genMips) {
+ Adapter2D adapt(texAlloc);
+ Adapter2D adapt2(texAlloc);
+ for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
+ adapt.setLOD(lod);
+ adapt2.setLOD(lod + 1);
+ mip565(adapt2, adapt);
+ }
+ }
+
+ return texAlloc;
+}
+
+RsAllocation rsi_AllocationCreateFromFile(Context *rsc, const char *file, bool genMips)
+{
+ bool use32bpp = false;
+
+ typedef struct _Win3xBitmapHeader
+ {
+ uint16_t type;
+ uint32_t totalSize;
+ uint32_t reserved;
+ uint32_t offset;
+ int32_t hdrSize; /* Size of this header in bytes */
+ int32_t width; /* Image width in pixels */
+ int32_t height; /* Image height in pixels */
+ int16_t planes; /* Number of color planes */
+ int16_t bpp; /* Number of bits per pixel */
+ /* Fields added for Windows 3.x follow this line */
+ int32_t compression; /* Compression methods used */
+ int32_t sizeOfBitmap; /* Size of bitmap in bytes */
+ int32_t horzResolution; /* Horizontal resolution in pixels per meter */
+ int32_t vertResolution; /* Vertical resolution in pixels per meter */
+ int32_t colorsUsed; /* Number of colors in the image */
+ int32_t colorsImportant; /* Minimum number of important colors */
+ } __attribute__((__packed__)) WIN3XBITMAPHEADER;
+
+ _Win3xBitmapHeader hdr;
+
+ FILE *f = fopen(file, "rb");
+ if (f == NULL) {
+ LOGE("rsAllocationCreateFromBitmap failed to open file %s", file);
+ return NULL;
+ }
+ memset(&hdr, 0, sizeof(hdr));
+ fread(&hdr, sizeof(hdr), 1, f);
+
+ if (hdr.bpp != 24) {
+ LOGE("Unsuported BMP type");
+ fclose(f);
+ return NULL;
+ }
+
+ int32_t texWidth = rsHigherPow2(hdr.width);
+ int32_t texHeight = rsHigherPow2(hdr.height);
+
+ if (use32bpp) {
+ rsi_TypeBegin(rsc, rsi_ElementGetPredefined(rsc, RS_ELEMENT_RGBA_8888));
+ } else {
+ rsi_TypeBegin(rsc, rsi_ElementGetPredefined(rsc, RS_ELEMENT_RGB_565));
+ }
+ rsi_TypeAdd(rsc, RS_DIMENSION_X, texWidth);
+ rsi_TypeAdd(rsc, RS_DIMENSION_Y, texHeight);
+ if (genMips) {
+ rsi_TypeAdd(rsc, RS_DIMENSION_LOD, 1);
+ }
+ RsType type = rsi_TypeCreate(rsc);
+
+ RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, type);
+ Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
+ texAlloc->incRef();
+ if (texAlloc == NULL) {
+ LOGE("Memory allocation failure");
+ fclose(f);
+ return NULL;
+ }
+
+ // offset to letterbox if height is not pow2
+ Adapter2D adapt(texAlloc);
+ uint8_t * fileInBuf = new uint8_t[texWidth * 3];
+ uint32_t yOffset = (hdr.width - hdr.height) / 2;
+
+ if (use32bpp) {
+ uint8_t *tmp = static_cast<uint8_t *>(adapt.getElement(0, yOffset));
+ for (int y=0; y < hdr.height; y++) {
+ fseek(f, hdr.offset + (y*hdr.width*3), SEEK_SET);
+ fread(fileInBuf, 1, hdr.width * 3, f);
+ for(int x=0; x < hdr.width; x++) {
+ tmp[0] = fileInBuf[x*3 + 2];
+ tmp[1] = fileInBuf[x*3 + 1];
+ tmp[2] = fileInBuf[x*3];
+ tmp[3] = 0xff;
+ tmp += 4;
+ }
+ }
+ } else {
+ uint16_t *tmp = static_cast<uint16_t *>(adapt.getElement(0, yOffset));
+ for (int y=0; y < hdr.height; y++) {
+ fseek(f, hdr.offset + (y*hdr.width*3), SEEK_SET);
+ fread(fileInBuf, 1, hdr.width * 3, f);
+ for(int x=0; x < hdr.width; x++) {
+ *tmp = rs888to565(fileInBuf[x*3 + 2], fileInBuf[x*3 + 1], fileInBuf[x*3]);
+ tmp++;
+ }
+ }
+ }
+
+ fclose(f);
+ delete [] fileInBuf;
+
+ if (genMips) {
+ Adapter2D adapt2(texAlloc);
+ for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
+ adapt.setLOD(lod);
+ adapt2.setLOD(lod + 1);
+ if (use32bpp) {
+ mip8888(adapt2, adapt);
+ } else {
+ mip565(adapt2, adapt);
+ }
+ }
+ }
+
+ return texAlloc;
+}
+
+
+void rsi_AllocationData(Context *rsc, RsAllocation va, const void *data)
+{
+ Allocation *a = static_cast<Allocation *>(va);
+ a->data(data);
+}
+
+void rsi_Allocation1DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t count, const void *data)
+{
+ Allocation *a = static_cast<Allocation *>(va);
+ a->subData(xoff, count, data);
+}
+
+void rsi_Allocation2DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data)
+{
+ Allocation *a = static_cast<Allocation *>(va);
+ a->subData(xoff, yoff, w, h, data);
+}
+
+
+}
+}
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
new file mode 100644
index 0000000..d0b91fd
--- /dev/null
+++ b/libs/rs/rsAllocation.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_STRUCTURED_ALLOCATION_H
+#define ANDROID_STRUCTURED_ALLOCATION_H
+
+#include "rsType.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+
+class Allocation : public ObjectBase
+{
+ // The graphics equilivent of malloc. The allocation contains a structure of elements.
+
+
+public:
+ // By policy this allocation will hold a pointer to the type
+ // but will not destroy it on destruction.
+ Allocation(const Type *);
+ virtual ~Allocation();
+
+ void setCpuWritable(bool);
+ void setGpuWritable(bool);
+ void setCpuReadable(bool);
+ void setGpuReadable(bool);
+
+ bool fixAllocation();
+
+ void * getPtr() const {return mPtr;}
+ const Type * getType() const {return mType.get();}
+
+ void uploadToTexture(uint32_t lodOffset = 0);
+ uint32_t getTextureID() const {return mTextureID;}
+
+ void uploadToBufferObject();
+ uint32_t getBufferObjectID() const {return mBufferID;}
+
+
+ void data(const void *data);
+ void subData(uint32_t xoff, uint32_t count, const void *data);
+ void subData(uint32_t xoff, uint32_t yoff,
+ uint32_t w, uint32_t h, const void *data);
+ void subData(uint32_t xoff, uint32_t yoff, uint32_t zoff,
+ uint32_t w, uint32_t h, uint32_t d, const void *data);
+
+protected:
+ ObjectBaseRef<const Type> mType;
+ void * mPtr;
+
+ // Usage restrictions
+ bool mCpuWrite;
+ bool mCpuRead;
+ bool mGpuWrite;
+ bool mGpuRead;
+
+ // more usage hint data from the application
+ // which can be used by a driver to pick the best memory type.
+ // Likely ignored for now
+ float mReadWriteRatio;
+ float mUpdateSize;
+
+
+ // Is this a legal structure to be used as a texture source.
+ // Initially this will require 1D or 2D and color data
+ bool mIsTexture;
+ uint32_t mTextureID;
+
+ // Is this a legal structure to be used as a vertex source.
+ // Initially this will require 1D and x(yzw). Additional per element data
+ // is allowed.
+ bool mIsVertexBuffer;
+ uint32_t mBufferID;
+
+};
+
+}
+}
+#endif
+
diff --git a/libs/rs/rsComponent.cpp b/libs/rs/rsComponent.cpp
new file mode 100644
index 0000000..a931811
--- /dev/null
+++ b/libs/rs/rsComponent.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#include "rsComponent.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Component::Component()
+{
+ mType = FLOAT;
+ mKind = NONE;
+ mIsNormalized = false;
+ mBits = 0;
+}
+
+Component::Component(
+ DataKind dk, DataType dt,
+ bool isNormalized, uint32_t bits)
+{
+ mType = dt;
+ mKind = dk;
+ mIsNormalized = isNormalized;
+ mBits = bits;
+}
+
+Component::~Component()
+{
+}
diff --git a/libs/rs/rsComponent.h b/libs/rs/rsComponent.h
new file mode 100644
index 0000000..205e575
--- /dev/null
+++ b/libs/rs/rsComponent.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_STRUCTURED_COMPONENT_H
+#define ANDROID_RS_STRUCTURED_COMPONENT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+#include "RenderScript.h"
+#include "rsObjectBase.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Component : public ObjectBase
+{
+public:
+ enum DataType {
+ FLOAT,
+ UNSIGNED,
+ SIGNED
+ };
+
+ enum DataKind {
+ NONE,
+ RED, GREEN, BLUE, ALPHA, LUMINANCE, INTENSITY,
+ X, Y, Z, W,
+ S, T, Q, R,
+ NX, NY, NZ,
+ INDEX,
+ USER
+ };
+
+
+ Component(DataKind dk, DataType dt, bool isNormalized, uint32_t bits);
+ virtual ~Component();
+
+ DataType getType() const {return mType;}
+ bool getIsNormalized() const {return mIsNormalized;}
+ DataKind getKind() const {return mKind;}
+ uint32_t getBits() const {return mBits;}
+
+protected:
+
+ DataType mType;
+ bool mIsNormalized;
+ DataKind mKind;
+ uint32_t mBits;
+
+private:
+ Component();
+};
+
+
+}
+}
+
+#endif //ANDROID_RS_STRUCTURED_COMPONENT_H
+
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
new file mode 100644
index 0000000..ec4a309
--- /dev/null
+++ b/libs/rs/rsContext.cpp
@@ -0,0 +1,313 @@
+/*
+ * 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.
+ */
+
+#include "rsDevice.h"
+#include "rsContext.h"
+#include "rsThreadIO.h"
+
+
+using namespace android;
+using namespace android::renderscript;
+
+Context * Context::gCon = NULL;
+
+void Context::initEGL()
+{
+ mNumConfigs = -1;
+
+ EGLint s_configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RED_SIZE, 5,
+ EGL_GREEN_SIZE, 6,
+ EGL_BLUE_SIZE, 5,
+ EGL_DEPTH_SIZE, 16,
+ EGL_NONE
+ };
+
+ LOGE("EGL 1");
+ mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ LOGE("EGL 2 %p", mDisplay);
+ eglInitialize(mDisplay, &mMajorVersion, &mMinorVersion);
+ LOGE("EGL 3 %i %i", mMajorVersion, mMinorVersion);
+ eglChooseConfig(mDisplay, s_configAttribs, &mConfig, 1, &mNumConfigs);
+ LOGE("EGL 4 %p", mConfig);
+
+ if (mWndSurface) {
+ mSurface = eglCreateWindowSurface(mDisplay, mConfig,
+ new EGLNativeWindowSurface(mWndSurface),
+ NULL);
+ } else {
+ mSurface = eglCreateWindowSurface(mDisplay, mConfig,
+ android_createDisplaySurface(),
+ NULL);
+ }
+
+ LOGE("EGL 5");
+ mContext = eglCreateContext(mDisplay, mConfig, NULL, NULL);
+ eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
+ eglQuerySurface(mDisplay, mSurface, EGL_WIDTH, &mWidth);
+ eglQuerySurface(mDisplay, mSurface, EGL_HEIGHT, &mHeight);
+ LOGE("EGL 9");
+
+}
+
+bool Context::runRootScript()
+{
+ rsAssert(mRootScript->mIsRoot);
+
+ glColor4f(1,1,1,1);
+ glEnable(GL_LIGHT0);
+ glViewport(0, 0, 320, 480);
+ float aspectH = 480.f / 320.f;
+
+ if(mRootScript->mIsOrtho) {
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrthof(0, 320, 480, 0, 0, 1);
+ glMatrixMode(GL_MODELVIEW);
+ } else {
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustumf(-1, 1, -aspectH, aspectH, 1, 100);
+ glRotatef(-90, 0,0,1);
+ glTranslatef(0, 0, -3);
+ glMatrixMode(GL_MODELVIEW);
+ }
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glDepthMask(GL_TRUE);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+ glClearColor(mRootScript->mClearColor[0],
+ mRootScript->mClearColor[1],
+ mRootScript->mClearColor[2],
+ mRootScript->mClearColor[3]);
+ glClearDepthf(mRootScript->mClearDepth);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ return mRootScript->run(this, 0);
+}
+
+void Context::setupCheck()
+{
+ if (mFragmentStore.get()) {
+ mFragmentStore->setupGL();
+ }
+ if (mFragment.get()) {
+ mFragment->setupGL();
+ }
+ if (mVertex.get()) {
+ mVertex->setupGL();
+ }
+
+}
+
+
+void * Context::threadProc(void *vrsc)
+{
+ Context *rsc = static_cast<Context *>(vrsc);
+
+ LOGE("TP 1");
+ gIO = new ThreadIO();
+
+ rsc->mServerCommands.init(128);
+ rsc->mServerReturns.init(128);
+
+ rsc->initEGL();
+
+ LOGE("TP 2");
+
+ rsc->mRunning = true;
+ bool mDraw = true;
+ while (!rsc->mExit) {
+ mDraw |= gIO->playCoreCommands(rsc);
+
+ if (!mDraw || !rsc->mRootScript.get()) {
+ usleep(10000);
+ continue;
+ }
+
+ if (rsc->mRootScript.get()) {
+ mDraw = rsc->runRootScript();
+ eglSwapBuffers(rsc->mDisplay, rsc->mSurface);
+ }
+ }
+
+ LOGE("TP 6");
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(rsc->mDisplay, rsc->mSurface);
+ eglTerminate(rsc->mDisplay);
+ return NULL;
+}
+
+Context::Context(Device *dev, Surface *sur)
+{
+ LOGE("CC 1");
+ dev->addContext(this);
+ mDev = dev;
+ mRunning = false;
+ mExit = false;
+
+ mServerCommands.init(256);
+ mServerReturns.init(256);
+
+ // see comment in header
+ gCon = this;
+
+ LOGE("CC 2");
+ int status;
+ pthread_attr_t threadAttr;
+
+ status = pthread_attr_init(&threadAttr);
+ if (status) {
+ LOGE("Failed to init thread attribute.");
+ return;
+ }
+
+ sched_param sparam;
+ sparam.sched_priority = ANDROID_PRIORITY_DISPLAY;
+ pthread_attr_setschedparam(&threadAttr, &sparam);
+
+ status = pthread_create(&mThreadId, &threadAttr, threadProc, this);
+ if (status) {
+ LOGE("Failed to start rs context thread.");
+ }
+
+ LOGE("CC 3");
+ mWndSurface = sur;
+ while(!mRunning) {
+ sleep(1);
+ }
+ LOGE("CC 4");
+
+ pthread_attr_destroy(&threadAttr);
+}
+
+Context::~Context()
+{
+ mExit = true;
+ void *res;
+
+ LOGE("DES 1");
+ int status = pthread_join(mThreadId, &res);
+ LOGE("DES 2");
+
+ if (mDev) {
+ mDev->removeContext(this);
+ }
+ LOGE("DES 3");
+}
+
+void Context::swapBuffers()
+{
+ eglSwapBuffers(mDisplay, mSurface);
+}
+
+void rsContextSwap(RsContext vrsc)
+{
+ Context *rsc = static_cast<Context *>(vrsc);
+ rsc->swapBuffers();
+}
+
+void Context::setRootScript(Script *s)
+{
+ mRootScript.set(s);
+}
+
+void Context::setFragmentStore(ProgramFragmentStore *pfs)
+{
+ mFragmentStore.set(pfs);
+ pfs->setupGL();
+}
+
+void Context::setFragment(ProgramFragment *pf)
+{
+ mFragment.set(pf);
+ pf->setupGL();
+}
+
+void Context::setVertex(ProgramVertex *pv)
+{
+ mVertex.set(pv);
+ pv->setupGL();
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+//
+
+namespace android {
+namespace renderscript {
+
+
+void rsi_ContextBindRootScript(Context *rsc, RsScript vs)
+{
+ Script *s = static_cast<Script *>(vs);
+ rsc->setRootScript(s);
+}
+
+void rsi_ContextBindSampler(Context *rsc, uint32_t slot, RsSampler vs)
+{
+ Sampler *s = static_cast<Sampler *>(vs);
+
+ if (slot > RS_MAX_SAMPLER_SLOT) {
+ LOGE("Invalid sampler slot");
+ return;
+ }
+
+ s->bindToContext(&rsc->mStateSampler, slot);
+}
+
+void rsi_ContextBindProgramFragmentStore(Context *rsc, RsProgramFragmentStore vpfs)
+{
+ ProgramFragmentStore *pfs = static_cast<ProgramFragmentStore *>(vpfs);
+ rsc->setFragmentStore(pfs);
+}
+
+void rsi_ContextBindProgramFragment(Context *rsc, RsProgramFragment vpf)
+{
+ ProgramFragment *pf = static_cast<ProgramFragment *>(vpf);
+ rsc->setFragment(pf);
+}
+
+void rsi_ContextBindProgramVertex(Context *rsc, RsProgramVertex vpv)
+{
+ ProgramVertex *pv = static_cast<ProgramVertex *>(vpv);
+ rsc->setVertex(pv);
+}
+
+
+
+}
+}
+
+
+RsContext rsContextCreate(RsDevice vdev, void *sur, uint32_t version)
+{
+ Device * dev = static_cast<Device *>(vdev);
+ Context *rsc = new Context(dev, (Surface *)sur);
+ return rsc;
+}
+
+void rsContextDestroy(RsContext vrsc)
+{
+ Context * rsc = static_cast<Context *>(vrsc);
+ delete rsc;
+}
+
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
new file mode 100644
index 0000000..64717e4
--- /dev/null
+++ b/libs/rs/rsContext.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_CONTEXT_H
+#define ANDROID_RS_CONTEXT_H
+
+#include <utils/Vector.h>
+#include <ui/EGLNativeWindowSurface.h>
+#include <ui/Surface.h>
+
+#include "rsType.h"
+#include "rsMatrix.h"
+#include "rsAllocation.h"
+#include "rsTriangleMesh.h"
+#include "rsDevice.h"
+#include "rsScriptC.h"
+#include "rsAllocation.h"
+#include "rsAdapter.h"
+#include "rsSampler.h"
+#include "rsProgramFragment.h"
+#include "rsProgramFragmentStore.h"
+#include "rsProgramVertex.h"
+
+#include "rsgApiStructs.h"
+#include "rsLocklessFifo.h"
+
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+class Context
+{
+public:
+ Context(Device *, Surface *);
+ ~Context();
+
+
+ //StructuredAllocationContext mStateAllocation;
+ ElementState mStateElement;
+ TypeState mStateType;
+ SamplerState mStateSampler;
+ ProgramFragmentState mStateFragment;
+ ProgramFragmentStoreState mStateFragmentStore;
+ ProgramVertexState mStateVertex;
+
+ TriangleMeshContext mStateTriangleMesh;
+
+ ScriptCState mScriptC;
+
+ static Context * getContext() {return gCon;}
+
+ void swapBuffers();
+ void setRootScript(Script *);
+ void setVertex(ProgramVertex *);
+ void setFragment(ProgramFragment *);
+ void setFragmentStore(ProgramFragmentStore *);
+
+ void updateSurface(void *sur);
+
+ const ProgramFragment * getFragment() {return mFragment.get();}
+ const ProgramFragmentStore * getFragmentStore() {return mFragmentStore.get();}
+
+ void setupCheck();
+
+protected:
+ Device *mDev;
+
+ EGLint mNumConfigs;
+ EGLint mMajorVersion;
+ EGLint mMinorVersion;
+ EGLConfig mConfig;
+ EGLContext mContext;
+ EGLSurface mSurface;
+ EGLint mWidth;
+ EGLint mHeight;
+ EGLDisplay mDisplay;
+
+ bool mRunning;
+ bool mExit;
+
+ LocklessCommandFifo mServerCommands;
+ LocklessCommandFifo mServerReturns;
+
+ pthread_t mThreadId;
+
+ ObjectBaseRef<Script> mRootScript;
+ ObjectBaseRef<ProgramFragment> mFragment;
+ ObjectBaseRef<ProgramVertex> mVertex;
+ ObjectBaseRef<ProgramFragmentStore> mFragmentStore;
+
+private:
+ Context();
+
+ void initEGL();
+
+ bool runRootScript();
+
+ static void * threadProc(void *);
+
+ // todo: put in TLS
+ static Context *gCon;
+ Surface *mWndSurface;
+};
+
+
+}
+}
+#endif
diff --git a/libs/rs/rsDevice.cpp b/libs/rs/rsDevice.cpp
new file mode 100644
index 0000000..1b3c41b
--- /dev/null
+++ b/libs/rs/rsDevice.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#include "rsDevice.h"
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+Device::Device()
+{
+
+}
+
+Device::~Device()
+{
+
+}
+
+void Device::addContext(Context *rsc)
+{
+ mContexts.add(rsc);
+}
+
+void Device::removeContext(Context *rsc)
+{
+ for (size_t idx=0; idx < mContexts.size(); idx++) {
+ if (mContexts[idx] == rsc) {
+ mContexts.removeAt(idx);
+ break;
+ }
+ }
+}
+
+
+
+RsDevice rsDeviceCreate()
+{
+ Device * d = new Device();
+ return d;
+}
+
+void rsDeviceDestroy(RsDevice dev)
+{
+ Device * d = static_cast<Device *>(dev);
+ delete d;
+
+}
+
diff --git a/libs/rs/rsDevice.h b/libs/rs/rsDevice.h
new file mode 100644
index 0000000..3de3ffa
--- /dev/null
+++ b/libs/rs/rsDevice.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_DEVICE_H
+#define ANDROID_RS_DEVICE_H
+
+#include <utils/Vector.h>
+
+//#include "StructuredComponent.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Context;
+
+class Device {
+public:
+ Device();
+ ~Device();
+
+ void addContext(Context *);
+ void removeContext(Context *);
+
+protected:
+ Vector<Context *> mContexts;
+
+
+};
+
+
+
+
+
+}
+}
+#endif
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
new file mode 100644
index 0000000..5a44f47
--- /dev/null
+++ b/libs/rs/rsElement.cpp
@@ -0,0 +1,434 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+#include <GLES/gl.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+void ElementState::initPredefined()
+{
+ Component * u_8 = new Component(Component::USER, Component::UNSIGNED, true, 8);
+ Component * i_8 = new Component(Component::USER, Component::SIGNED, true, 8);
+ Component * u_16 = new Component(Component::USER, Component::UNSIGNED, true, 16);
+ Component * i_16 = new Component(Component::USER, Component::SIGNED, true, 16);
+ Component * u_32 = new Component(Component::USER, Component::UNSIGNED, true, 32);
+ Component * i_32 = new Component(Component::USER, Component::SIGNED, true, 32);
+ Component * f_32 = new Component(Component::USER, Component::FLOAT, true, 32);
+
+
+ Component * r_4 = new Component(Component::RED, Component::UNSIGNED, true, 4);
+ Component * r_5 = new Component(Component::RED, Component::UNSIGNED, true, 5);
+ Component * r_8 = new Component(Component::RED, Component::UNSIGNED, true, 8);
+
+ Component * g_4 = new Component(Component::GREEN, Component::UNSIGNED, true, 4);
+ Component * g_5 = new Component(Component::GREEN, Component::UNSIGNED, true, 5);
+ Component * g_6 = new Component(Component::GREEN, Component::UNSIGNED, true, 6);
+ Component * g_8 = new Component(Component::GREEN, Component::UNSIGNED, true, 8);
+
+ Component * b_4 = new Component(Component::BLUE, Component::UNSIGNED, true, 4);
+ Component * b_5 = new Component(Component::BLUE, Component::UNSIGNED, true, 5);
+ Component * b_8 = new Component(Component::BLUE, Component::UNSIGNED, true, 8);
+
+ Component * a_1 = new Component(Component::ALPHA, Component::UNSIGNED, true, 1);
+ Component * a_4 = new Component(Component::ALPHA, Component::UNSIGNED, true, 4);
+ Component * a_8 = new Component(Component::ALPHA, Component::UNSIGNED, true, 8);
+
+ Component * idx_16 = new Component(Component::INDEX, Component::UNSIGNED, false, 16);
+ Component * idx_32 = new Component(Component::INDEX, Component::UNSIGNED, false, 32);
+
+ Component * x = new Component(Component::X, Component::FLOAT, false, 32);
+ Component * y = new Component(Component::Y, Component::FLOAT, false, 32);
+ Component * z = new Component(Component::Z, Component::FLOAT, false, 32);
+
+ Component * nx = new Component(Component::NX, Component::FLOAT, false, 32);
+ Component * ny = new Component(Component::NY, Component::FLOAT, false, 32);
+ Component * nz = new Component(Component::NZ, Component::FLOAT, false, 32);
+
+ Component * s = new Component(Component::S, Component::FLOAT, false, 32);
+ Component * t = new Component(Component::T, Component::FLOAT, false, 32);
+
+ Element * e;
+
+ e = new Element(1);
+ e->setComponent(0, u_8);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_U8, e));
+
+ e = new Element(1);
+ e->setComponent(0, i_8);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_I8, e));
+
+ e = new Element(1);
+ e->setComponent(0, u_16);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_U16, e));
+
+ e = new Element(1);
+ e->setComponent(0, i_16);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_I16, e));
+
+ e = new Element(1);
+ e->setComponent(0, u_32);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_U32, e));
+
+ e = new Element(1);
+ e->setComponent(0, i_32);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_I32, e));
+
+ e = new Element(1);
+ e->setComponent(0, f_32);
+ mPredefinedList.add(Predefined(RS_ELEMENT_USER_FLOAT, e));
+
+ e = new Element(1);
+ e->setComponent(0, a_8);
+ mPredefinedList.add(Predefined(RS_ELEMENT_A_8, e));
+
+ e = new Element(3);
+ e->setComponent(0, r_5);
+ e->setComponent(1, g_6);
+ e->setComponent(2, b_5);
+ mPredefinedList.add(Predefined(RS_ELEMENT_RGB_565, e));
+
+ e = new Element(4);
+ e->setComponent(0, r_5);
+ e->setComponent(1, g_5);
+ e->setComponent(2, b_5);
+ e->setComponent(3, a_1);
+ mPredefinedList.add(Predefined(RS_ELEMENT_RGBA_5551, e));
+
+ e = new Element(4);
+ e->setComponent(0, r_4);
+ e->setComponent(1, g_4);
+ e->setComponent(2, b_4);
+ e->setComponent(3, a_4);
+ mPredefinedList.add(Predefined(RS_ELEMENT_RGBA_4444, e));
+
+ e = new Element(3);
+ e->setComponent(0, r_8);
+ e->setComponent(1, g_8);
+ e->setComponent(2, b_8);
+ mPredefinedList.add(Predefined(RS_ELEMENT_RGB_888, e));
+
+ e = new Element(4);
+ e->setComponent(0, r_8);
+ e->setComponent(1, g_8);
+ e->setComponent(2, b_8);
+ e->setComponent(3, a_8);
+ mPredefinedList.add(Predefined(RS_ELEMENT_RGBA_8888, e));
+
+ e = new Element(1);
+ e->setComponent(0, idx_16);
+ mPredefinedList.add(Predefined(RS_ELEMENT_INDEX_16, e));
+
+ e = new Element(1);
+ e->setComponent(0, idx_32);
+ mPredefinedList.add(Predefined(RS_ELEMENT_INDEX_32, e));
+
+ e = new Element(2);
+ e->setComponent(0, x);
+ e->setComponent(1, y);
+ mPredefinedList.add(Predefined(RS_ELEMENT_XY_F32, e));
+
+ e = new Element(3);
+ e->setComponent(0, x);
+ e->setComponent(1, y);
+ e->setComponent(2, z);
+ mPredefinedList.add(Predefined(RS_ELEMENT_XYZ_F32, e));
+
+ e = new Element(4);
+ e->setComponent(0, s);
+ e->setComponent(1, t);
+ e->setComponent(2, x);
+ e->setComponent(3, y);
+ mPredefinedList.add(Predefined(RS_ELEMENT_ST_XY_F32, e));
+
+ e = new Element(5);
+ e->setComponent(0, s);
+ e->setComponent(1, t);
+ e->setComponent(2, x);
+ e->setComponent(3, y);
+ e->setComponent(4, z);
+ mPredefinedList.add(Predefined(RS_ELEMENT_ST_XYZ_F32, e));
+
+ e = new Element(6);
+ e->setComponent(0, nx);
+ e->setComponent(1, ny);
+ e->setComponent(2, nz);
+ e->setComponent(3, x);
+ e->setComponent(4, y);
+ e->setComponent(5, z);
+ mPredefinedList.add(Predefined(RS_ELEMENT_NORM_XYZ_F32, e));
+
+ e = new Element(8);
+ e->setComponent(0, nx);
+ e->setComponent(1, ny);
+ e->setComponent(2, nz);
+ e->setComponent(3, s);
+ e->setComponent(4, t);
+ e->setComponent(5, x);
+ e->setComponent(6, y);
+ e->setComponent(7, z);
+ mPredefinedList.add(Predefined(RS_ELEMENT_NORM_ST_XYZ_F32, e));
+}
+
+
+Element::Element()
+{
+ mComponents = NULL;
+ mComponentCount = 0;
+}
+
+Element::Element(uint32_t count)
+{
+ mComponents = new ObjectBaseRef<Component> [count];
+ mComponentCount = count;
+}
+
+Element::~Element()
+{
+ clear();
+}
+
+void Element::clear()
+{
+ delete [] mComponents;
+ mComponents = NULL;
+ mComponentCount = 0;
+}
+
+void Element::setComponent(uint32_t idx, Component *c)
+{
+ rsAssert(!mComponents[idx].get());
+ rsAssert(idx < mComponentCount);
+ mComponents[idx].set(c);
+ c->incRef();
+}
+
+
+size_t Element::getSizeBits() const
+{
+ size_t total = 0;
+ for (size_t ct=0; ct < mComponentCount; ct++) {
+ total += mComponents[ct]->getBits();
+ }
+ return total;
+}
+
+size_t Element::getComponentOffsetBits(uint32_t componentNumber) const
+{
+ size_t offset = 0;
+ for (uint32_t ct = 0; ct < componentNumber; ct++) {
+ offset += mComponents[ct]->getBits();
+ }
+ return offset;
+}
+
+uint32_t Element::getGLType() const
+{
+ int bits[4];
+
+ if (mComponentCount > 4) {
+ return 0;
+ }
+
+ for (uint32_t ct=0; ct < mComponentCount; ct++) {
+ bits[ct] = mComponents[ct]->getBits();
+ if (mComponents[ct]->getType() != Component::UNSIGNED) {
+ return 0;
+ }
+ if (!mComponents[ct]->getIsNormalized()) {
+ return 0;
+ }
+ }
+
+ switch(mComponentCount) {
+ case 1:
+ if (bits[0] == 8) {
+ return GL_UNSIGNED_BYTE;
+ }
+ return 0;
+ case 2:
+ if ((bits[0] == 8) &&
+ (bits[1] == 8)) {
+ return GL_UNSIGNED_BYTE;
+ }
+ return 0;
+ case 3:
+ if ((bits[0] == 8) &&
+ (bits[1] == 8) &&
+ (bits[2] == 8)) {
+ return GL_UNSIGNED_BYTE;
+ }
+ if ((bits[0] == 5) &&
+ (bits[1] == 6) &&
+ (bits[2] == 5)) {
+ return GL_UNSIGNED_SHORT_5_6_5;
+ }
+ return 0;
+ case 4:
+ if ((bits[0] == 8) &&
+ (bits[1] == 8) &&
+ (bits[2] == 8) &&
+ (bits[3] == 8)) {
+ return GL_UNSIGNED_BYTE;
+ }
+ if ((bits[0] == 4) &&
+ (bits[1] == 4) &&
+ (bits[2] == 4) &&
+ (bits[3] == 4)) {
+ return GL_UNSIGNED_SHORT_4_4_4_4;
+ }
+ if ((bits[0] == 5) &&
+ (bits[1] == 5) &&
+ (bits[2] == 5) &&
+ (bits[3] == 1)) {
+ return GL_UNSIGNED_SHORT_5_5_5_1;
+ }
+ }
+ return 0;
+}
+
+uint32_t Element::getGLFormat() const
+{
+ switch(mComponentCount) {
+ case 1:
+ if (mComponents[0]->getKind() == Component::ALPHA) {
+ return GL_ALPHA;
+ }
+ if (mComponents[0]->getKind() == Component::LUMINANCE) {
+ return GL_LUMINANCE;
+ }
+ break;
+ case 2:
+ if ((mComponents[0]->getKind() == Component::LUMINANCE) &&
+ (mComponents[1]->getKind() == Component::ALPHA)) {
+ return GL_LUMINANCE_ALPHA;
+ }
+ break;
+ case 3:
+ if ((mComponents[0]->getKind() == Component::RED) &&
+ (mComponents[1]->getKind() == Component::GREEN) &&
+ (mComponents[2]->getKind() == Component::BLUE)) {
+ return GL_RGB;
+ }
+ break;
+ case 4:
+ if ((mComponents[0]->getKind() == Component::RED) &&
+ (mComponents[1]->getKind() == Component::GREEN) &&
+ (mComponents[2]->getKind() == Component::BLUE) &&
+ (mComponents[3]->getKind() == Component::ALPHA)) {
+ return GL_RGBA;
+ }
+ break;
+ }
+ return 0;
+}
+
+
+ElementState::ElementState()
+{
+}
+
+ElementState::~ElementState()
+{
+}
+
+/////////////////////////////////////////
+//
+
+namespace android {
+namespace renderscript {
+
+void rsi_ElementBegin(Context *rsc)
+{
+ rsc->mStateElement.mComponentBuildList.clear();
+}
+
+void rsi_ElementAddPredefined(Context *rsc, RsElementPredefined predef)
+{
+ ElementState * sec = &rsc->mStateElement;
+
+ RsElement ve = rsi_ElementGetPredefined(rsc, predef);
+ const Element *e = static_cast<const Element *>(ve);
+
+ for(size_t ct = 0; ct < sec->mPredefinedList[predef].mElement->getComponentCount(); ct++) {
+ sec->mComponentBuildList.add(sec->mPredefinedList[predef].mElement->getComponent(ct));
+ }
+}
+
+RsElement rsi_ElementGetPredefined(Context *rsc, RsElementPredefined predef)
+{
+ ElementState * sec = &rsc->mStateElement;
+
+ if (!sec->mPredefinedList.size()) {
+ sec->initPredefined();
+ }
+
+ if ((predef < 0) ||
+ (static_cast<uint32_t>(predef) >= sec->mPredefinedList.size())) {
+ LOGE("rsElementGetPredefined: Request for bad predefined type");
+ // error
+ return NULL;
+ }
+
+ rsAssert(sec->mPredefinedList[predef].mEnum == predef);
+ Element * e = sec->mPredefinedList[predef].mElement;
+ e->incRef();
+ return e;
+}
+
+void rsi_ElementAdd(Context *rsc, RsDataKind dk, RsDataType dt, bool isNormalized, size_t bits)
+{
+ ElementState * sec = &rsc->mStateElement;
+
+}
+
+RsElement rsi_ElementCreate(Context *rsc)
+{
+ ElementState * sec = &rsc->mStateElement;
+
+ Element *se = new Element(sec->mComponentBuildList.size());
+ sec->mAllElements.add(se);
+
+ for (size_t ct = 0; ct < se->getComponentCount(); ct++) {
+ se->setComponent(ct, sec->mComponentBuildList[ct]);
+ }
+
+ rsc->mStateElement.mComponentBuildList.clear();
+ se->incRef();
+
+ LOGE("Create %p", se);
+ return se;
+}
+
+void rsi_ElementDestroy(Context *rsc, RsElement vse)
+{
+ ElementState * sec = &rsc->mStateElement;
+ Element * se = static_cast<Element *>(vse);
+
+ for (size_t ct = 0; ct < sec->mAllElements.size(); ct++) {
+ if (sec->mAllElements[ct] == se) {
+ sec->mAllElements.removeAt(ct);
+ break;
+ }
+ }
+ se->decRef();
+}
+
+
+}
+}
diff --git a/libs/rs/rsElement.h b/libs/rs/rsElement.h
new file mode 100644
index 0000000..2434977
--- /dev/null
+++ b/libs/rs/rsElement.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_STRUCTURED_ELEMENT_H
+#define ANDROID_STRUCTURED_ELEMENT_H
+
+#include <utils/Vector.h>
+
+#include "rsComponent.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+// An element is a group of Components that occupies one cell in a structure.
+class Element : public ObjectBase
+{
+public:
+ Element(uint32_t count);
+ ~Element();
+
+
+ void setComponent(uint32_t idx, Component *c);
+
+ uint32_t getGLType() const;
+ uint32_t getGLFormat() const;
+
+
+ size_t getSizeBits() const;
+ size_t getSizeBytes() const {
+ return (getSizeBits() + 7) >> 3;
+ }
+
+ size_t getComponentOffsetBits(uint32_t componentNumber) const;
+ size_t getComponentOffsetBytes(uint32_t componentNumber) const {
+ return (getComponentOffsetBits(componentNumber) + 7) >> 3;
+ }
+
+ uint32_t getComponentCount() const {return mComponentCount;}
+ Component * getComponent(uint32_t idx) const {return mComponents[idx].get();}
+
+protected:
+ // deallocate any components that are part of this element.
+ void clear();
+
+ size_t mComponentCount;
+ ObjectBaseRef<Component> * mComponents;
+ //uint32_t *mOffsetTable;
+
+ Element();
+};
+
+
+class ElementState {
+public:
+ ElementState();
+ ~ElementState();
+
+ Vector<Element *> mAllElements;
+ Vector<Component *> mComponentBuildList;
+
+
+
+ struct Predefined {
+ Predefined() {
+ mElement = NULL;
+ }
+ Predefined(RsElementPredefined en, Element *e) {
+ mEnum = en;
+ mElement = e;
+ }
+ RsElementPredefined mEnum;
+ Element * mElement;
+ };
+ Vector<Predefined> mPredefinedList;
+
+ void initPredefined();
+
+};
+
+
+}
+}
+#endif //ANDROID_STRUCTURED_ELEMENT_H
diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp
new file mode 100644
index 0000000..67ab434
--- /dev/null
+++ b/libs/rs/rsLocklessFifo.cpp
@@ -0,0 +1,182 @@
+/*
+ * 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.
+ */
+
+#include "rsLocklessFifo.h"
+
+using namespace android;
+
+#include <utils/Log.h>
+
+LocklessCommandFifo::LocklessCommandFifo()
+{
+}
+
+LocklessCommandFifo::~LocklessCommandFifo()
+{
+}
+
+bool LocklessCommandFifo::init(uint32_t sizeInBytes)
+{
+ // Add room for a buffer reset command
+ mBuffer = static_cast<uint8_t *>(malloc(sizeInBytes + 4));
+ if (!mBuffer) {
+ LOGE("LocklessFifo allocation failure");
+ return false;
+ }
+
+ int status = pthread_mutex_init(&mMutex, NULL);
+ if (status) {
+ LOGE("LocklessFifo mutex init failure");
+ free(mBuffer);
+ return false;
+ }
+ status = pthread_cond_init(&mCondition, NULL);
+ if (status) {
+ LOGE("LocklessFifo condition init failure");
+ pthread_mutex_destroy(&mMutex);
+ free(mBuffer);
+ return false;
+ }
+
+ mSize = sizeInBytes;
+ mPut = mBuffer;
+ mGet = mBuffer;
+ mEnd = mBuffer + (sizeInBytes) - 1;
+ dumpState("init");
+ return true;
+}
+
+uint32_t LocklessCommandFifo::getFreeSpace() const
+{
+ int32_t freeSpace = 0;
+ //dumpState("getFreeSpace");
+
+ if (mPut >= mGet) {
+ freeSpace = mEnd - mPut;
+ } else {
+ freeSpace = mGet - mPut;
+ }
+
+ if (freeSpace < 0) {
+ freeSpace = 0;
+ }
+
+ //LOGE("free %i", freeSpace);
+ return freeSpace;
+}
+
+bool LocklessCommandFifo::isEmpty() const
+{
+ return mPut == mGet;
+}
+
+
+void * LocklessCommandFifo::reserve(uint32_t sizeInBytes)
+{
+ // Add space for command header and loop token;
+ sizeInBytes += 8;
+
+ //dumpState("reserve");
+ if (getFreeSpace() < sizeInBytes) {
+ makeSpace(sizeInBytes);
+ }
+
+ return mPut + 4;
+}
+
+void LocklessCommandFifo::commit(uint32_t command, uint32_t sizeInBytes)
+{
+ //LOGE("commit cmd %i size %i", command, sizeInBytes);
+ //dumpState("commit 1");
+ reinterpret_cast<uint16_t *>(mPut)[0] = command;
+ reinterpret_cast<uint16_t *>(mPut)[1] = sizeInBytes;
+ mPut += ((sizeInBytes + 3) & ~3) + 4;
+ //dumpState("commit 2");
+
+}
+
+void LocklessCommandFifo::commitSync(uint32_t command, uint32_t sizeInBytes)
+{
+ commit(command, sizeInBytes);
+ flush();
+}
+
+void LocklessCommandFifo::flush()
+{
+ //dumpState("flush 1");
+ while(mPut != mGet) {
+ usleep(1);
+ }
+ //dumpState("flush 2");
+}
+
+const void * LocklessCommandFifo::get(uint32_t *command, uint32_t *bytesData)
+{
+ while(1) {
+ while(isEmpty()) {
+ usleep(10);
+ }
+ //dumpState("get 3");
+
+ *command = reinterpret_cast<const uint16_t *>(mGet)[0];
+ *bytesData = reinterpret_cast<const uint16_t *>(mGet)[1];
+ //LOGE("Got %i, %i", *command, *bytesData);
+
+ if (*command) {
+ // non-zero command is valid
+ return mGet+4;
+ }
+
+ // zero command means reset to beginning.
+ mGet = mBuffer;
+ }
+}
+
+void LocklessCommandFifo::next()
+{
+ uint32_t bytes = reinterpret_cast<const uint16_t *>(mGet)[1];
+ mGet += ((bytes + 3) & ~3) + 4;
+ //dumpState("next");
+}
+
+void LocklessCommandFifo::makeSpace(uint32_t bytes)
+{
+ //dumpState("make space");
+ if ((mPut+bytes) > mEnd) {
+ // Need to loop regardless of where get is.
+ while((mGet > mPut) && (mBuffer+4 >= mGet)) {
+ sleep(1);
+ }
+
+ // Toss in a reset then the normal wait for space will do the rest.
+ reinterpret_cast<uint16_t *>(mPut)[0] = 0;
+ reinterpret_cast<uint16_t *>(mPut)[1] = 0;
+ mPut = mBuffer;
+ }
+
+ // it will fit here so we just need to wait for space.
+ while(getFreeSpace() < bytes) {
+ sleep(1);
+ }
+
+}
+
+void LocklessCommandFifo::dumpState(const char *s) const
+{
+ LOGE("%s put %p, get %p, buf %p, end %p", s, mPut, mGet, mBuffer, mEnd);
+}
+
+
diff --git a/libs/rs/rsLocklessFifo.h b/libs/rs/rsLocklessFifo.h
new file mode 100644
index 0000000..ddef382
--- /dev/null
+++ b/libs/rs/rsLocklessFifo.h
@@ -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.
+ */
+
+#ifndef ANDROID_RS_LOCKLESS_FIFO_H
+#define ANDROID_RS_LOCKLESS_FIFO_H
+
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+namespace android {
+
+
+// A simple FIFO to be used as a producer / consumer between two
+// threads. One is writer and one is reader. The common cases
+// will not require locking. It is not threadsafe for multiple
+// readers or writers by design.
+
+class LocklessCommandFifo
+{
+public:
+ bool init(uint32_t size);
+
+ LocklessCommandFifo();
+ ~LocklessCommandFifo();
+
+
+protected:
+ uint8_t * volatile mPut;
+ uint8_t * volatile mGet;
+ uint8_t * mBuffer;
+ uint8_t * mEnd;
+ uint8_t mSize;
+
+ pthread_mutex_t mMutex;
+ pthread_cond_t mCondition;
+
+public:
+ void * reserve(uint32_t bytes);
+ void commit(uint32_t command, uint32_t bytes);
+ void commitSync(uint32_t command, uint32_t bytes);
+
+ void flush();
+ const void * get(uint32_t *command, uint32_t *bytesData);
+ void next();
+
+ void makeSpace(uint32_t bytes);
+
+ bool isEmpty() const;
+ uint32_t getFreeSpace() const;
+
+
+private:
+ void dumpState(const char *) const;
+};
+
+
+}
+#endif
diff --git a/libs/rs/rsMatrix.cpp b/libs/rs/rsMatrix.cpp
new file mode 100644
index 0000000..e68d5ac
--- /dev/null
+++ b/libs/rs/rsMatrix.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+#include "rsMatrix.h"
+
+#include "stdlib.h"
+#include "string.h"
+#include "math.h"
+
+#include <utils/Log.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+
+
+void Matrix::loadIdentity()
+{
+ set(0, 0, 1);
+ set(1, 0, 0);
+ set(2, 0, 0);
+ set(3, 0, 0);
+
+ set(0, 1, 0);
+ set(1, 1, 1);
+ set(2, 1, 0);
+ set(3, 1, 0);
+
+ set(0, 2, 0);
+ set(1, 2, 0);
+ set(2, 2, 1);
+ set(3, 2, 0);
+
+ set(0, 3, 0);
+ set(1, 3, 0);
+ set(2, 3, 0);
+ set(3, 3, 1);
+}
+
+void Matrix::load(const float *v)
+{
+ memcpy(m, v, sizeof(m));
+}
+
+void Matrix::load(const Matrix *v)
+{
+ memcpy(m, v->m, sizeof(m));
+}
+
+void Matrix::loadRotate(float rot, float x, float y, float z)
+{
+ float c, s;
+ m[3] = 0;
+ m[7] = 0;
+ m[11]= 0;
+ m[12]= 0;
+ m[13]= 0;
+ m[14]= 0;
+ m[15]= 1;
+ rot *= float(M_PI / 180.0f);
+ c = cosf(rot);
+ s = sinf(rot);
+
+ const float len = sqrtf(x*x + y*y + z*z);
+ if (!(len != 1)) {
+ const float recipLen = 1.f / len;
+ x *= recipLen;
+ y *= recipLen;
+ z *= recipLen;
+ }
+ const float nc = 1.0f - c;
+ const float xy = x * y;
+ const float yz = y * z;
+ const float zx = z * x;
+ const float xs = x * s;
+ const float ys = y * s;
+ const float zs = z * s;
+ m[ 0] = x*x*nc + c;
+ m[ 4] = xy*nc - zs;
+ m[ 8] = zx*nc + ys;
+ m[ 1] = xy*nc + zs;
+ m[ 5] = y*y*nc + c;
+ m[ 9] = yz*nc - xs;
+ m[ 2] = zx*nc - ys;
+ m[ 6] = yz*nc + xs;
+ m[10] = z*z*nc + c;
+}
+
+void Matrix::loadScale(float x, float y, float z)
+{
+ loadIdentity();
+ m[0] = x;
+ m[5] = y;
+ m[10] = z;
+}
+
+void Matrix::loadTranslate(float x, float y, float z)
+{
+ loadIdentity();
+ m[12] = x;
+ m[13] = y;
+ m[14] = z;
+}
+
+void Matrix::loadMultiply(const Matrix *lhs, const Matrix *rhs)
+{
+ for (int i=0 ; i<4 ; i++) {
+ float ri0 = 0;
+ float ri1 = 0;
+ float ri2 = 0;
+ float ri3 = 0;
+ for (int j=0 ; j<4 ; j++) {
+ const float rhs_ij = rhs->get(i,j);
+ ri0 += lhs->get(j,0) * rhs_ij;
+ ri1 += lhs->get(j,1) * rhs_ij;
+ ri2 += lhs->get(j,2) * rhs_ij;
+ ri3 += lhs->get(j,3) * rhs_ij;
+ }
+ set(i,0, ri0);
+ set(i,1, ri1);
+ set(i,2, ri2);
+ set(i,3, ri3);
+ }
+}
+
+
diff --git a/libs/rs/rsMatrix.h b/libs/rs/rsMatrix.h
new file mode 100644
index 0000000..619b494
--- /dev/null
+++ b/libs/rs/rsMatrix.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_MATRIX_H
+#define ANDROID_RS_MATRIX_H
+
+
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+struct Matrix
+{
+ float m[16];
+
+ inline float get(int i, int j) const {
+ return m[i*4 + j];
+ }
+
+ inline void set(int i, int j, float v) {
+ m[i*4 + j] = v;
+ }
+
+ void loadIdentity();
+ void load(const float *);
+ void load(const Matrix *);
+
+ void loadRotate(float rot, float x, float y, float z);
+ void loadScale(float x, float y, float z);
+ void loadTranslate(float x, float y, float z);
+ void loadMultiply(const Matrix *lhs, const Matrix *rhs);
+
+ void multiply(const Matrix *rhs) {
+ Matrix tmp;
+ tmp.loadMultiply(this, rhs);
+ load(&tmp);
+ }
+ void rotate(float rot, float x, float y, float z) {
+ Matrix tmp;
+ tmp.loadRotate(rot, x, y, z);
+ multiply(&tmp);
+ }
+ void scale(float x, float y, float z) {
+ Matrix tmp;
+ tmp.loadScale(x, y, z);
+ multiply(&tmp);
+ }
+ void translate(float x, float y, float z) {
+ Matrix tmp;
+ tmp.loadTranslate(x, y, z);
+ multiply(&tmp);
+ }
+
+
+
+};
+
+
+
+}
+}
+
+
+
+
+#endif
+
+
+
+
diff --git a/libs/rs/rsObjectBase.cpp b/libs/rs/rsObjectBase.cpp
new file mode 100644
index 0000000..f9cb9c8
--- /dev/null
+++ b/libs/rs/rsObjectBase.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#include "rsObjectBase.h"
+#include <utils/Log.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+ObjectBase::ObjectBase()
+{
+ mRefCount = 0;
+}
+
+ObjectBase::~ObjectBase()
+{
+ rsAssert(!mRefCount);
+}
+
+void ObjectBase::incRef() const
+{
+ mRefCount ++;
+ //LOGE("ObjectBase %p inc ref %i", this, mRefCount);
+}
+
+void ObjectBase::decRef() const
+{
+ rsAssert(mRefCount > 0);
+ mRefCount --;
+ //LOGE("ObjectBase %p dec ref %i", this, mRefCount);
+ if (!mRefCount) {
+ delete this;
+ }
+}
+
diff --git a/libs/rs/rsObjectBase.h b/libs/rs/rsObjectBase.h
new file mode 100644
index 0000000..7761e49
--- /dev/null
+++ b/libs/rs/rsObjectBase.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_OBJECT_BASE_H
+#define ANDROID_RS_OBJECT_BASE_H
+
+#include "rsUtils.h"
+
+
+namespace android {
+namespace renderscript {
+
+// An element is a group of Components that occupies one cell in a structure.
+class ObjectBase
+{
+public:
+ ObjectBase();
+ virtual ~ObjectBase();
+
+ void incRef() const;
+ void decRef() const;
+
+private:
+ mutable int32_t mRefCount;
+
+
+};
+
+template<class T>
+class ObjectBaseRef
+{
+public:
+ ObjectBaseRef() {
+ mRef = NULL;
+ }
+
+ ~ObjectBaseRef() {
+ clear();
+ }
+
+ void set(T *ref) {
+ if (mRef != ref) {
+ clear();
+ mRef = ref;
+ ref->incRef();
+ }
+ }
+
+ void clear() {
+ if (mRef) {
+ mRef->decRef();
+ }
+ mRef = NULL;
+ }
+
+ inline T * get() const {
+ return mRef;
+ }
+
+ inline T * operator-> () const {
+ return mRef;
+ }
+
+protected:
+ T * mRef;
+
+private:
+ ObjectBaseRef(const ObjectBaseRef &) {};
+
+};
+
+
+}
+}
+
+#endif //ANDROID_RS_OBJECT_BASE_H
+
diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp
new file mode 100644
index 0000000..5a83fb7
--- /dev/null
+++ b/libs/rs/rsProgram.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+#include "rsProgram.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Program::Program(Element *in, Element *out)
+{
+ mElementIn.set(in);
+ mElementOut.set(out);
+
+
+}
+
+Program::~Program()
+{
+}
+
+
+void Program::setAllocation(Allocation *alloc)
+{
+ mConstants.set(alloc);
+ mDirty = true;
+}
+
+void Program::setupGL()
+{
+
+}
+
+
diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h
new file mode 100644
index 0000000..913fdd2
--- /dev/null
+++ b/libs/rs/rsProgram.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_PROGRAM_H
+#define ANDROID_RS_PROGRAM_H
+
+#include "rsObjectBase.h"
+#include "rsElement.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+
+class Program : public ObjectBase
+{
+public:
+ Program(Element *in, Element *out);
+ virtual ~Program();
+
+
+ void setAllocation(Allocation *);
+
+ virtual void setupGL();
+
+protected:
+ // Components not listed in "in" will be passed though
+ // unless overwritten by components in out.
+ ObjectBaseRef<Element> mElementIn;
+ ObjectBaseRef<Element> mElementOut;
+
+ ObjectBaseRef<Allocation> mConstants;
+
+ bool mDirty;
+
+};
+
+
+
+}
+}
+#endif
+
+
+
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
new file mode 100644
index 0000000..3d316ea
--- /dev/null
+++ b/libs/rs/rsProgramFragment.cpp
@@ -0,0 +1,219 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+#include "rsProgramFragment.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+ProgramFragment::ProgramFragment(Element *in, Element *out) :
+ Program(in, out)
+{
+ for (uint32_t ct=0; ct < MAX_TEXTURE; ct++) {
+ mEnvModes[ct] = RS_TEX_ENV_MODE_REPLACE;
+ mTextureDimensions[ct] = 2;
+ }
+ mTextureEnableMask = 0;
+}
+
+ProgramFragment::~ProgramFragment()
+{
+}
+
+void ProgramFragment::setupGL()
+{
+ for (uint32_t ct=0; ct < MAX_TEXTURE; ct++) {
+ glActiveTexture(GL_TEXTURE0 + ct);
+ if (!(mTextureEnableMask & (1 << ct)) ||
+ //!mSamplers[ct].get() ||
+ !mTextures[ct].get()) {
+
+ glDisable(GL_TEXTURE_2D);
+ continue;
+ }
+
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, mTextures[ct]->getTextureID());
+
+ switch(mEnvModes[ct]) {
+ case RS_TEX_ENV_MODE_REPLACE:
+ glTexEnvf(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ break;
+ case RS_TEX_ENV_MODE_MODULATE:
+ glTexEnvf(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ break;
+ case RS_TEX_ENV_MODE_DECAL:
+ glTexEnvf(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_DECAL);
+ break;
+ }
+
+ if (mSamplers[ct].get()) {
+ mSamplers[ct]->setupGL();
+ } else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ }
+ }
+ glActiveTexture(GL_TEXTURE0);
+}
+
+
+void ProgramFragment::bindTexture(uint32_t slot, Allocation *a)
+{
+ if (slot >= MAX_TEXTURE) {
+ LOGE("Attempt to bind a texture to a slot > MAX_TEXTURE");
+ return;
+ }
+
+ mTextures[slot].set(a);
+}
+
+void ProgramFragment::bindSampler(uint32_t slot, Sampler *s)
+{
+ if (slot >= MAX_TEXTURE) {
+ LOGE("Attempt to bind a Sampler to a slot > MAX_TEXTURE");
+ return;
+ }
+
+ mSamplers[slot].set(s);
+}
+
+void ProgramFragment::setType(uint32_t slot, const Element *e, uint32_t dim)
+{
+ if (slot >= MAX_TEXTURE) {
+ LOGE("Attempt to setType to a slot > MAX_TEXTURE");
+ return;
+ }
+
+ if (dim >= 4) {
+ LOGE("Attempt to setType to a dimension > 3");
+ return;
+ }
+
+ mTextureFormats[slot].set(e);
+ mTextureDimensions[slot] = dim;
+}
+
+void ProgramFragment::setEnvMode(uint32_t slot, RsTexEnvMode env)
+{
+ if (slot >= MAX_TEXTURE) {
+ LOGE("Attempt to setEnvMode to a slot > MAX_TEXTURE");
+ return;
+ }
+
+ mEnvModes[slot] = env;
+}
+
+void ProgramFragment::setTexEnable(uint32_t slot, bool enable)
+{
+ if (slot >= MAX_TEXTURE) {
+ LOGE("Attempt to setEnvMode to a slot > MAX_TEXTURE");
+ return;
+ }
+
+ uint32_t bit = 1 << slot;
+ mTextureEnableMask &= ~bit;
+ if (enable) {
+ mTextureEnableMask |= bit;
+ }
+}
+
+
+
+ProgramFragmentState::ProgramFragmentState()
+{
+ mPF = NULL;
+}
+
+ProgramFragmentState::~ProgramFragmentState()
+{
+ delete mPF;
+
+}
+
+
+
+namespace android {
+namespace renderscript {
+
+void rsi_ProgramFragmentBegin(Context * rsc, RsElement in, RsElement out)
+{
+ delete rsc->mStateFragment.mPF;
+ rsc->mStateFragment.mPF = new ProgramFragment((Element *)in, (Element *)out);
+}
+
+void rsi_ProgramFragmentBindTexture(Context *rsc, RsProgramFragment vpf, uint32_t slot, RsAllocation a)
+{
+ ProgramFragment *pf = static_cast<ProgramFragment *>(vpf);
+ pf->bindTexture(slot, static_cast<Allocation *>(a));
+
+ //LOGE("%p %p", pf, rsc->getFragment());
+ if (pf == rsc->getFragment()) {
+ pf->setupGL();
+ }
+}
+
+void rsi_ProgramFragmentBindSampler(Context *rsc, RsProgramFragment vpf, uint32_t slot, RsSampler s)
+{
+ ProgramFragment *pf = static_cast<ProgramFragment *>(vpf);
+ pf->bindSampler(slot, static_cast<Sampler *>(s));
+
+ if (pf == rsc->getFragment()) {
+ pf->setupGL();
+ }
+}
+
+void rsi_ProgramFragmentSetType(Context *rsc, uint32_t slot, RsType vt)
+{
+ const Type *t = static_cast<const Type *>(vt);
+ uint32_t dim = 1;
+ if (t->getDimY()) {
+ dim ++;
+ if (t->getDimZ()) {
+ dim ++;
+ }
+ }
+
+ rsc->mStateFragment.mPF->setType(slot, t->getElement(), dim);
+}
+
+void rsi_ProgramFragmentSetEnvMode(Context *rsc, uint32_t slot, RsTexEnvMode env)
+{
+ rsc->mStateFragment.mPF->setEnvMode(slot, env);
+}
+
+void rsi_ProgramFragmentSetTexEnable(Context *rsc, uint32_t slot, bool enable)
+{
+ rsc->mStateFragment.mPF->setTexEnable(slot, enable);
+}
+
+RsProgramFragment rsi_ProgramFragmentCreate(Context *rsc)
+{
+ ProgramFragment *pf = rsc->mStateFragment.mPF;
+ pf->incRef();
+ rsc->mStateFragment.mPF = 0;
+ return pf;
+}
+
+
+
+}
+}
+
diff --git a/libs/rs/rsProgramFragment.h b/libs/rs/rsProgramFragment.h
new file mode 100644
index 0000000..cc08aea
--- /dev/null
+++ b/libs/rs/rsProgramFragment.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_PROGRAM_FRAGMENT_H
+#define ANDROID_RS_PROGRAM_FRAGMENT_H
+
+#include "rsProgram.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+class ProgramFragment : public Program
+{
+public:
+ const static uint32_t MAX_TEXTURE = 2;
+ const static uint32_t MAX_CONSTANTS = 2;
+
+
+
+ ProgramFragment(Element *in, Element *out);
+ virtual ~ProgramFragment();
+
+ virtual void setupGL();
+
+
+
+ void bindTexture(uint32_t slot, Allocation *);
+ void bindSampler(uint32_t slot, Sampler *);
+ void setType(uint32_t slot, const Element *, uint32_t dim);
+
+ void setEnvMode(uint32_t slot, RsTexEnvMode);
+ void setTexEnable(uint32_t slot, bool);
+
+
+
+protected:
+ // The difference between Textures and Constants is how they are accessed
+ // Texture lookups go though a sampler which in effect converts normalized
+ // coordinates into type specific. Multiple samples may also be taken
+ // and filtered.
+ //
+ // Constants are strictly accessed by programetic loads.
+ ObjectBaseRef<Allocation> mTextures[MAX_TEXTURE];
+ ObjectBaseRef<Sampler> mSamplers[MAX_TEXTURE];
+ ObjectBaseRef<const Element> mTextureFormats[MAX_TEXTURE];
+ uint32_t mTextureDimensions[MAX_TEXTURE];
+
+
+ ObjectBaseRef<Allocation> mConstants[MAX_CONSTANTS];
+ ObjectBaseRef<Type> mConstantTypes[MAX_CONSTANTS];
+
+
+ // Hacks to create a program for now
+ RsTexEnvMode mEnvModes[MAX_TEXTURE];
+ uint32_t mTextureEnableMask;
+
+
+
+
+
+};
+
+class ProgramFragmentState
+{
+public:
+ ProgramFragmentState();
+ ~ProgramFragmentState();
+
+ ProgramFragment *mPF;
+
+ ObjectBaseRef<Type> mTextureTypes[ProgramFragment::MAX_TEXTURE];
+
+
+};
+
+
+}
+}
+#endif
+
+
+
+
diff --git a/libs/rs/rsProgramFragmentStore.cpp b/libs/rs/rsProgramFragmentStore.cpp
new file mode 100644
index 0000000..7f5d5f4
--- /dev/null
+++ b/libs/rs/rsProgramFragmentStore.cpp
@@ -0,0 +1,252 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+#include "rsProgramFragmentStore.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+ProgramFragmentStore::ProgramFragmentStore(Element *in, Element *out) :
+ Program(in, out)
+{
+ mDitherEnable = true;
+ mBlendEnable = false;
+ mColorRWriteEnable = true;
+ mColorGWriteEnable = true;
+ mColorBWriteEnable = true;
+ mColorAWriteEnable = true;
+ mBlendSrc = GL_ONE;
+ mBlendDst = GL_ZERO;
+
+
+ mDepthTestEnable = false;
+ mDepthWriteEnable = true;
+ mDepthFunc = GL_LESS;
+
+
+}
+
+ProgramFragmentStore::~ProgramFragmentStore()
+{
+}
+
+void ProgramFragmentStore::setupGL()
+{
+ glColorMask(mColorRWriteEnable,
+ mColorGWriteEnable,
+ mColorBWriteEnable,
+ mColorAWriteEnable);
+ if (mBlendEnable) {
+ glEnable(GL_BLEND);
+ glBlendFunc(mBlendSrc, mBlendDst);
+ } else {
+ glDisable(GL_BLEND);
+ }
+
+ glDepthMask(mDepthWriteEnable);
+ if(mDepthTestEnable) {
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(mDepthFunc);
+ } else {
+ glDisable(GL_DEPTH_TEST);
+ }
+
+ if (mDitherEnable) {
+ glEnable(GL_DITHER);
+ } else {
+ glDisable(GL_DITHER);
+ }
+
+
+}
+
+void ProgramFragmentStore::setDitherEnable(bool enable)
+{
+ mDitherEnable = enable;
+}
+
+void ProgramFragmentStore::setDepthFunc(RsDepthFunc func)
+{
+ mDepthTestEnable = true;
+
+ switch(func) {
+ case RS_DEPTH_FUNC_ALWAYS:
+ mDepthTestEnable = false;
+ mDepthFunc = GL_ALWAYS;
+ break;
+ case RS_DEPTH_FUNC_LESS:
+ mDepthFunc = GL_LESS;
+ break;
+ case RS_DEPTH_FUNC_LEQUAL:
+ mDepthFunc = GL_LEQUAL;
+ break;
+ case RS_DEPTH_FUNC_GREATER:
+ mDepthFunc = GL_GREATER;
+ break;
+ case RS_DEPTH_FUNC_GEQUAL:
+ mDepthFunc = GL_GEQUAL;
+ break;
+ case RS_DEPTH_FUNC_EQUAL:
+ mDepthFunc = GL_EQUAL;
+ break;
+ case RS_DEPTH_FUNC_NOTEQUAL:
+ mDepthFunc = GL_NOTEQUAL;
+ break;
+ }
+}
+
+void ProgramFragmentStore::setDepthMask(bool mask)
+{
+ mDepthWriteEnable = mask;
+}
+
+void ProgramFragmentStore::setBlendFunc(RsBlendSrcFunc src, RsBlendDstFunc dst)
+{
+ mBlendEnable = true;
+ if ((src == RS_BLEND_SRC_ONE) &&
+ (dst == RS_BLEND_DST_ZERO)) {
+ mBlendEnable = false;
+ }
+
+ switch(src) {
+ case RS_BLEND_SRC_ZERO:
+ mBlendSrc = GL_ZERO;
+ break;
+ case RS_BLEND_SRC_ONE:
+ mBlendSrc = GL_ONE;
+ break;
+ case RS_BLEND_SRC_DST_COLOR:
+ mBlendSrc = GL_DST_COLOR;
+ break;
+ case RS_BLEND_SRC_ONE_MINUS_DST_COLOR:
+ mBlendSrc = GL_ONE_MINUS_DST_COLOR;
+ break;
+ case RS_BLEND_SRC_SRC_ALPHA:
+ mBlendSrc = GL_SRC_ALPHA;
+ break;
+ case RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA:
+ mBlendSrc = GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case RS_BLEND_SRC_DST_ALPHA:
+ mBlendSrc = GL_DST_ALPHA;
+ break;
+ case RS_BLEND_SRC_ONE_MINUS_DST_ALPHA:
+ mBlendSrc = GL_ONE_MINUS_DST_ALPHA;
+ break;
+ case RS_BLEND_SRC_SRC_ALPHA_SATURATE:
+ mBlendSrc = GL_SRC_ALPHA_SATURATE;
+ break;
+ }
+
+ switch(dst) {
+ case RS_BLEND_DST_ZERO:
+ mBlendDst = GL_ZERO;
+ break;
+ case RS_BLEND_DST_ONE:
+ mBlendDst = GL_ONE;
+ break;
+ case RS_BLEND_DST_SRC_COLOR:
+ mBlendDst = GL_SRC_COLOR;
+ break;
+ case RS_BLEND_DST_ONE_MINUS_SRC_COLOR:
+ mBlendDst = GL_ONE_MINUS_SRC_COLOR;
+ break;
+ case RS_BLEND_DST_SRC_ALPHA:
+ mBlendDst = GL_SRC_ALPHA;
+ break;
+ case RS_BLEND_DST_ONE_MINUS_SRC_ALPHA:
+ mBlendDst = GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case RS_BLEND_DST_DST_ALPHA:
+ mBlendDst = GL_DST_ALPHA;
+ break;
+ case RS_BLEND_DST_ONE_MINUS_DST_ALPHA:
+ mBlendDst = GL_ONE_MINUS_DST_ALPHA;
+ break;
+ }
+}
+
+void ProgramFragmentStore::setColorMask(bool r, bool g, bool b, bool a)
+{
+ mColorRWriteEnable = r;
+ mColorGWriteEnable = g;
+ mColorBWriteEnable = b;
+ mColorAWriteEnable = a;
+}
+
+
+ProgramFragmentStoreState::ProgramFragmentStoreState()
+{
+ mPFS = NULL;
+}
+
+ProgramFragmentStoreState::~ProgramFragmentStoreState()
+{
+ delete mPFS;
+
+}
+
+
+
+namespace android {
+namespace renderscript {
+
+void rsi_ProgramFragmentStoreBegin(Context * rsc, RsElement in, RsElement out)
+{
+ delete rsc->mStateFragmentStore.mPFS;
+ rsc->mStateFragmentStore.mPFS = new ProgramFragmentStore((Element *)in, (Element *)out);
+
+}
+
+void rsi_ProgramFragmentStoreDepthFunc(Context *rsc, RsDepthFunc func)
+{
+ rsc->mStateFragmentStore.mPFS->setDepthFunc(func);
+}
+
+void rsi_ProgramFragmentStoreDepthMask(Context *rsc, bool mask)
+{
+ rsc->mStateFragmentStore.mPFS->setDepthMask(mask);
+}
+
+void rsi_ProgramFragmentStoreColorMask(Context *rsc, bool r, bool g, bool b, bool a)
+{
+ rsc->mStateFragmentStore.mPFS->setColorMask(r, g, b, a);
+}
+
+void rsi_ProgramFragmentStoreBlendFunc(Context *rsc, RsBlendSrcFunc src, RsBlendDstFunc dst)
+{
+ rsc->mStateFragmentStore.mPFS->setBlendFunc(src, dst);
+}
+
+RsProgramFragmentStore rsi_ProgramFragmentStoreCreate(Context *rsc)
+{
+ ProgramFragmentStore *pfs = rsc->mStateFragmentStore.mPFS;
+ pfs->incRef();
+ rsc->mStateFragmentStore.mPFS = 0;
+
+ return pfs;
+}
+
+void rsi_ProgramFragmentStoreDither(Context *rsc, bool enable)
+{
+ rsc->mStateFragmentStore.mPFS->setDitherEnable(enable);
+}
+
+
+}
+}
diff --git a/libs/rs/rsProgramFragmentStore.h b/libs/rs/rsProgramFragmentStore.h
new file mode 100644
index 0000000..bbd0f38
--- /dev/null
+++ b/libs/rs/rsProgramFragmentStore.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_PROGRAM_FRAGMENT_STORE_H
+#define ANDROID_RS_PROGRAM_FRAGMENT_STORE_H
+
+#include "rsProgram.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+class ProgramFragmentStore : public Program
+{
+public:
+
+
+
+ ProgramFragmentStore(Element *in, Element *out);
+ virtual ~ProgramFragmentStore();
+
+ virtual void setupGL();
+
+
+ void setDepthFunc(RsDepthFunc);
+ void setDepthMask(bool);
+
+ void setBlendFunc(RsBlendSrcFunc src, RsBlendDstFunc dst);
+ void setColorMask(bool, bool, bool, bool);
+
+ void setDitherEnable(bool);
+
+protected:
+ bool mDitherEnable;
+
+ bool mBlendEnable;
+ bool mColorRWriteEnable;
+ bool mColorGWriteEnable;
+ bool mColorBWriteEnable;
+ bool mColorAWriteEnable;
+ int32_t mBlendSrc;
+ int32_t mBlendDst;
+
+
+
+ bool mDepthTestEnable;
+ bool mDepthWriteEnable;
+ int32_t mDepthFunc;
+
+
+
+ bool mStencilTestEnable;
+
+
+
+};
+
+class ProgramFragmentStoreState
+{
+public:
+ ProgramFragmentStoreState();
+ ~ProgramFragmentStoreState();
+
+ ProgramFragmentStore *mPFS;
+
+
+};
+
+
+}
+}
+#endif
+
+
+
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
new file mode 100644
index 0000000..8e2b82d
--- /dev/null
+++ b/libs/rs/rsProgramVertex.cpp
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+#include "rsProgramVertex.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+ProgramVertex::ProgramVertex(Element *in, Element *out) :
+ Program(in, out)
+{
+ mTextureMatrixEnable = false;
+ mProjectionEnable = false;
+ mTransformEnable = false;
+}
+
+ProgramVertex::~ProgramVertex()
+{
+}
+
+void ProgramVertex::setupGL()
+{
+ const float *f = static_cast<const float *>(mConstants[0]->getPtr());
+
+ glMatrixMode(GL_TEXTURE);
+ if (mTextureMatrixEnable) {
+ glLoadMatrixf(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET]);
+ } else {
+ glLoadIdentity();
+ }
+
+
+ glMatrixMode(GL_PROJECTION);
+ if (mProjectionEnable) {
+ //glLoadMatrixf(&f[OFFSET_PROJECTION]);
+ } else {
+ }
+
+ glMatrixMode(GL_MODELVIEW);
+ if (mTransformEnable) {
+ glLoadMatrixf(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET]);
+ } else {
+ glLoadIdentity();
+ }
+
+}
+
+void ProgramVertex::setConstantType(uint32_t slot, const Type *t)
+{
+ mConstantTypes[slot].set(t);
+}
+
+void ProgramVertex::bindAllocation(uint32_t slot, Allocation *a)
+{
+ mConstants[slot].set(a);
+}
+
+
+ProgramVertexState::ProgramVertexState()
+{
+ mPV = NULL;
+}
+
+ProgramVertexState::~ProgramVertexState()
+{
+ delete mPV;
+}
+
+
+
+namespace android {
+namespace renderscript {
+
+void rsi_ProgramVertexBegin(Context *rsc, RsElement in, RsElement out)
+{
+ delete rsc->mStateVertex.mPV;
+ rsc->mStateVertex.mPV = new ProgramVertex((Element *)in, (Element *)out);
+}
+
+RsProgramVertex rsi_ProgramVertexCreate(Context *rsc)
+{
+ ProgramVertex *pv = rsc->mStateVertex.mPV;
+ pv->incRef();
+ rsc->mStateVertex.mPV = 0;
+
+ return pv;
+}
+
+void rsi_ProgramVertexBindAllocation(Context *rsc, RsProgramVertex vpgm, uint32_t slot, RsAllocation constants)
+{
+ ProgramVertex *pv = static_cast<ProgramVertex *>(vpgm);
+ pv->bindAllocation(slot, static_cast<Allocation *>(constants));
+}
+
+void rsi_ProgramVertexSetType(Context *rsc, uint32_t slot, RsType constants)
+{
+ rsc->mStateVertex.mPV->setConstantType(slot, static_cast<const Type *>(constants));
+}
+
+void rsi_ProgramVertexSetCameraMode(Context *rsc, bool ortho)
+{
+ rsc->mStateVertex.mPV->setProjectionEnabled(!ortho);
+}
+
+void rsi_ProgramVertexSetTextureMatrixEnable(Context *rsc, bool enable)
+{
+ rsc->mStateVertex.mPV->setTextureMatrixEnable(enable);
+}
+
+void rsi_ProgramVertexSetModelMatrixEnable(Context *rsc, bool enable)
+{
+ rsc->mStateVertex.mPV->setTransformEnable(enable);
+}
+
+
+
+}
+}
diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h
new file mode 100644
index 0000000..cd46900
--- /dev/null
+++ b/libs/rs/rsProgramVertex.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_PROGRAM_VERTEX_H
+#define ANDROID_RS_PROGRAM_VERTEX_H
+
+#include "rsProgram.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+class ProgramVertex : public Program
+{
+public:
+ const static uint32_t MAX_CONSTANTS = 2;
+
+ ProgramVertex(Element *in, Element *out);
+ virtual ~ProgramVertex();
+
+ virtual void setupGL();
+
+
+ void setConstantType(uint32_t slot, const Type *);
+ void bindAllocation(uint32_t slot, Allocation *);
+ void setTextureMatrixEnable(bool e) {mTextureMatrixEnable = e;}
+ void setProjectionEnabled(bool e) {mProjectionEnable = e;}
+ void setTransformEnable(bool e) {mTransformEnable = e;}
+
+protected:
+ bool mDirty;
+
+ ObjectBaseRef<Allocation> mConstants[MAX_CONSTANTS];
+ ObjectBaseRef<const Type> mConstantTypes[MAX_CONSTANTS];
+
+ // Hacks to create a program for now
+ bool mTextureMatrixEnable;
+ bool mProjectionEnable;
+ bool mTransformEnable;
+
+};
+
+
+class ProgramVertexState
+{
+public:
+ ProgramVertexState();
+ ~ProgramVertexState();
+
+ ProgramVertex *mPV;
+
+ //ObjectBaseRef<Type> mTextureTypes[ProgramFragment::MAX_TEXTURE];
+
+
+};
+
+
+}
+}
+#endif
+
+
diff --git a/libs/rs/rsSampler.cpp b/libs/rs/rsSampler.cpp
new file mode 100644
index 0000000..d89346e
--- /dev/null
+++ b/libs/rs/rsSampler.cpp
@@ -0,0 +1,160 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <utils/Log.h>
+
+#include "rsContext.h"
+#include "rsSampler.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Sampler::Sampler()
+{
+ // Should not get called.
+ rsAssert(0);
+}
+
+Sampler::Sampler(RsSamplerValue magFilter,
+ RsSamplerValue minFilter,
+ RsSamplerValue wrapS,
+ RsSamplerValue wrapT,
+ RsSamplerValue wrapR)
+{
+ mMagFilter = magFilter;
+ mMinFilter = minFilter;
+ mWrapS = wrapS;
+ mWrapT = wrapT;
+ mWrapR = wrapR;
+}
+
+Sampler::~Sampler()
+{
+}
+
+void Sampler::setupGL()
+{
+ GLenum trans[] = {
+ GL_NEAREST, //RS_SAMPLER_NEAREST,
+ GL_LINEAR, //RS_SAMPLER_LINEAR,
+ GL_LINEAR_MIPMAP_LINEAR, //RS_SAMPLER_LINEAR_MIP_LINEAR,
+ GL_REPEAT, //RS_SAMPLER_WRAP,
+ GL_CLAMP_TO_EDGE, //RS_SAMPLER_CLAMP
+
+ };
+
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, trans[mMagFilter]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, trans[mWrapS]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, trans[mWrapT]);
+
+}
+
+void Sampler::bindToContext(SamplerState *ss, uint32_t slot)
+{
+ ss->mSamplers[slot].set(this);
+ mBoundSlot = slot;
+}
+
+void Sampler::unbindFromContext(SamplerState *ss)
+{
+ int32_t slot = mBoundSlot;
+ mBoundSlot = -1;
+ ss->mSamplers[slot].clear();
+}
+
+void SamplerState::setupGL()
+{
+ for (uint32_t ct=0; ct < RS_MAX_SAMPLER_SLOT; ct++) {
+ Sampler *s = mSamplers[ct].get();
+ if (s) {
+ s->setupGL();
+ } else {
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+ }
+}
+
+////////////////////////////////
+
+namespace android {
+namespace renderscript {
+
+
+void rsi_SamplerBegin(Context *rsc)
+{
+ SamplerState * ss = &rsc->mStateSampler;
+
+ ss->mMagFilter = RS_SAMPLER_LINEAR;
+ ss->mMinFilter = RS_SAMPLER_LINEAR;
+ ss->mWrapS = RS_SAMPLER_WRAP;
+ ss->mWrapT = RS_SAMPLER_WRAP;
+ ss->mWrapR = RS_SAMPLER_WRAP;
+}
+
+void rsi_SamplerSet(Context *rsc, RsSamplerParam param, RsSamplerValue value)
+{
+ SamplerState * ss = &rsc->mStateSampler;
+
+ switch(param) {
+ case RS_SAMPLER_MAG_FILTER:
+ ss->mMagFilter = value;
+ break;
+ case RS_SAMPLER_MIN_FILTER:
+ ss->mMinFilter = value;
+ break;
+ case RS_SAMPLER_WRAP_S:
+ ss->mWrapS = value;
+ break;
+ case RS_SAMPLER_WRAP_T:
+ ss->mWrapT = value;
+ break;
+ case RS_SAMPLER_WRAP_R:
+ ss->mWrapR = value;
+ break;
+ }
+
+}
+
+RsSampler rsi_SamplerCreate(Context *rsc)
+{
+ SamplerState * ss = &rsc->mStateSampler;
+
+
+ Sampler * s = new Sampler(ss->mMagFilter,
+ ss->mMinFilter,
+ ss->mWrapS,
+ ss->mWrapT,
+ ss->mWrapR);
+ return s;
+}
+
+void rsi_SamplerDestroy(Context *rsc, RsSampler vs)
+{
+ Sampler * s = static_cast<Sampler *>(vs);
+ s->decRef();
+
+}
+
+
+}}
diff --git a/libs/rs/rsSampler.h b/libs/rs/rsSampler.h
new file mode 100644
index 0000000..45d8c61
--- /dev/null
+++ b/libs/rs/rsSampler.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_SAMPLER_H
+#define ANDROID_RS_SAMPLER_H
+
+#include <math.h>
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include "rsAllocation.h"
+#include "RenderScript.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+const static uint32_t RS_MAX_SAMPLER_SLOT = 16;
+
+class SamplerState;
+
+class Sampler : public ObjectBase
+{
+public:
+ Sampler(RsSamplerValue magFilter,
+ RsSamplerValue minFilter,
+ RsSamplerValue wrapS,
+ RsSamplerValue wrapT,
+ RsSamplerValue wrapR);
+
+ virtual ~Sampler();
+
+ void bind(Allocation *);
+ void setupGL();
+
+ void bindToContext(SamplerState *, uint32_t slot);
+ void unbindFromContext(SamplerState *);
+
+protected:
+ RsSamplerValue mMagFilter;
+ RsSamplerValue mMinFilter;
+ RsSamplerValue mWrapS;
+ RsSamplerValue mWrapT;
+ RsSamplerValue mWrapR;
+
+ int32_t mBoundSlot;
+
+private:
+ Sampler();
+
+};
+
+
+class SamplerState
+{
+public:
+
+ RsSamplerValue mMagFilter;
+ RsSamplerValue mMinFilter;
+ RsSamplerValue mWrapS;
+ RsSamplerValue mWrapT;
+ RsSamplerValue mWrapR;
+
+
+ ObjectBaseRef<Sampler> mSamplers[RS_MAX_SAMPLER_SLOT];
+
+ void setupGL();
+
+};
+
+
+
+}
+}
+#endif //ANDROID_RS_SAMPLER_H
+
+
+
diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp
new file mode 100644
index 0000000..24a630c
--- /dev/null
+++ b/libs/rs/rsScript.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+Script::Script()
+{
+ mClearColor[0] = 0;
+ mClearColor[1] = 0;
+ mClearColor[2] = 0;
+ mClearColor[3] = 1;
+ mClearDepth = 1;
+}
+
+Script::~Script()
+{
+}
+
+namespace android {
+namespace renderscript {
+
+
+void rsi_ScriptDestroy(Context * rsc, RsScript vs)
+{
+ Script *s = static_cast<Script *>(vs);
+ s->decRef();
+}
+
+void rsi_ScriptBindAllocation(Context * rsc, RsScript vs, RsAllocation va, uint32_t slot)
+{
+ Script *s = static_cast<Script *>(vs);
+ s->mSlots[slot].set(static_cast<Allocation *>(va));
+}
+
+
+}
+}
+
diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h
new file mode 100644
index 0000000..0229860
--- /dev/null
+++ b/libs/rs/rsScript.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_SCRIPT_H
+#define ANDROID_RS_SCRIPT_H
+
+#include "rsAllocation.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+
+class Script : public ObjectBase
+{
+public:
+
+ Script();
+ virtual ~Script();
+
+
+ bool mIsRoot;
+ bool mIsOrtho;
+
+ float mClearColor[4];
+ float mClearDepth;
+ uint32_t mClearStencil;
+
+
+ const Type * mConstantBufferTypes;
+ uint32_t mCounstantBufferCount;
+
+ ObjectBaseRef<Allocation> mSlots[16];
+
+ virtual bool run(Context *, uint32_t launchID) = 0;
+};
+
+
+
+}
+}
+#endif
+
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
new file mode 100644
index 0000000..be0191b
--- /dev/null
+++ b/libs/rs/rsScriptC.cpp
@@ -0,0 +1,529 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+#include "rsScriptC.h"
+#include "rsMatrix.h"
+
+#include "acc/acc.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+ScriptC::ScriptC()
+{
+ mAccScript = NULL;
+ mScript = NULL;
+ mScriptText = NULL;
+ mScriptTextLength = 0;
+}
+
+ScriptC::~ScriptC()
+{
+ if (mAccScript) {
+ accDeleteScript(mAccScript);
+ }
+}
+
+extern "C" void matrixLoadIdentity(void *con, rsc_Matrix *mat)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->loadIdentity();
+}
+
+extern "C" void matrixLoadFloat(void *con, rsc_Matrix *mat, const float *f)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->load(f);
+}
+
+extern "C" void matrixLoadMat(void *con, rsc_Matrix *mat, const rsc_Matrix *newmat)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->load(reinterpret_cast<const Matrix *>(newmat));
+}
+
+extern "C" void matrixLoadRotate(void *con, rsc_Matrix *mat, float rot, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->loadRotate(rot, x, y, z);
+}
+
+extern "C" void matrixLoadScale(void *con, rsc_Matrix *mat, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->loadScale(x, y, z);
+}
+
+extern "C" void matrixLoadTranslate(void *con, rsc_Matrix *mat, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->loadTranslate(x, y, z);
+}
+
+extern "C" void matrixLoadMultiply(void *con, rsc_Matrix *mat, const rsc_Matrix *lhs, const rsc_Matrix *rhs)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->loadMultiply(reinterpret_cast<const Matrix *>(lhs),
+ reinterpret_cast<const Matrix *>(rhs));
+}
+
+extern "C" void matrixMultiply(void *con, rsc_Matrix *mat, const rsc_Matrix *rhs)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->multiply(reinterpret_cast<const Matrix *>(rhs));
+}
+
+extern "C" void matrixRotate(void *con, rsc_Matrix *mat, float rot, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->rotate(rot, x, y, z);
+}
+
+extern "C" void matrixScale(void *con, rsc_Matrix *mat, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->scale(x, y, z);
+}
+
+extern "C" void matrixTranslate(void *con, rsc_Matrix *mat, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->translate(x, y, z);
+}
+
+
+extern "C" const void * loadVp(void *vp, uint32_t bank, uint32_t offset)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ return &static_cast<const uint8_t *>(env->mScript->mSlots[bank]->getPtr())[offset];
+}
+
+extern "C" float loadF(void *vp, uint32_t bank, uint32_t offset)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ //LOGE("bank %i, offset %i", bank, offset);
+ //LOGE("%p", env->mScript->mSlots[bank]->getPtr());
+ return static_cast<const float *>(env->mScript->mSlots[bank]->getPtr())[offset];
+}
+
+extern "C" int32_t loadI32(void *vp, uint32_t bank, uint32_t offset)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ return static_cast<const int32_t *>(env->mScript->mSlots[bank]->getPtr())[offset];
+}
+
+extern "C" uint32_t loadU32(void *vp, uint32_t bank, uint32_t offset)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ return static_cast<const uint32_t *>(env->mScript->mSlots[bank]->getPtr())[offset];
+}
+
+extern "C" void loadEnvVec4(void *vp, uint32_t bank, uint32_t offset, rsc_Vector4 *v)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ memcpy(v, &static_cast<const float *>(env->mScript->mSlots[bank]->getPtr())[offset], sizeof(rsc_Vector4));
+}
+
+extern "C" void loadEnvMatrix(void *vp, uint32_t bank, uint32_t offset, rsc_Matrix *m)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ memcpy(m, &static_cast<const float *>(env->mScript->mSlots[bank]->getPtr())[offset], sizeof(rsc_Matrix));
+}
+
+
+extern "C" void storeF(void *vp, uint32_t bank, uint32_t offset, float v)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ static_cast<float *>(env->mScript->mSlots[bank]->getPtr())[offset] = v;
+}
+
+extern "C" void storeI32(void *vp, uint32_t bank, uint32_t offset, int32_t v)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ static_cast<int32_t *>(env->mScript->mSlots[bank]->getPtr())[offset] = v;
+}
+
+extern "C" void storeU32(void *vp, uint32_t bank, uint32_t offset, uint32_t v)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ static_cast<uint32_t *>(env->mScript->mSlots[bank]->getPtr())[offset] = v;
+}
+
+extern "C" void storeEnvVec4(void *vp, uint32_t bank, uint32_t offset, const rsc_Vector4 *v)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ memcpy(&static_cast<float *>(env->mScript->mSlots[bank]->getPtr())[offset], v, sizeof(rsc_Vector4));
+}
+
+extern "C" void storeEnvMatrix(void *vp, uint32_t bank, uint32_t offset, const rsc_Matrix *m)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ memcpy(&static_cast<float *>(env->mScript->mSlots[bank]->getPtr())[offset], m, sizeof(rsc_Matrix));
+}
+
+
+extern "C" void color(void *vp, float r, float g, float b, float a)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ glColor4f(r, g, b, a);
+}
+
+extern "C" void renderTriangleMesh(void *vp, RsTriangleMesh mesh)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ rsi_TriangleMeshRender(env->mContext, mesh);
+}
+
+extern "C" void renderTriangleMeshRange(void *vp, RsTriangleMesh mesh, uint32_t start, uint32_t count)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ rsi_TriangleMeshRenderRange(env->mContext, mesh, start, count);
+}
+
+extern "C" void materialDiffuse(void *vp, float r, float g, float b, float a)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ float v[] = {r, g, b, a};
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, v);
+}
+
+extern "C" void materialSpecular(void *vp, float r, float g, float b, float a)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ float v[] = {r, g, b, a};
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, v);
+}
+
+extern "C" void lightPosition(void *vp, float x, float y, float z, float w)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ float v[] = {x, y, z, w};
+ glLightfv(GL_LIGHT0, GL_POSITION, v);
+}
+
+extern "C" void materialShininess(void *vp, float s)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &s);
+}
+
+extern "C" void uploadToTexture(void *vp, RsAllocation va, uint32_t baseMipLevel)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ rsi_AllocationUploadToTexture(env->mContext, va, baseMipLevel);
+}
+
+extern "C" void enable(void *vp, uint32_t p)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ glEnable(p);
+}
+
+extern "C" void disable(void *vp, uint32_t p)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ glDisable(p);
+}
+
+extern "C" uint32_t scriptRand(void *vp, uint32_t max)
+{
+ return (uint32_t)(((float)rand()) * max / RAND_MAX);
+}
+
+// Assumes (GL_FIXED) x,y,z (GL_UNSIGNED_BYTE)r,g,b,a
+extern "C" void drawTriangleArray(void *vp, RsAllocation alloc, uint32_t count)
+{
+ const Allocation *a = (const Allocation *)alloc;
+ const uint32_t *ptr = (const uint32_t *)a->getPtr();
+
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ env->mContext->setupCheck();
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+
+ glVertexPointer(2, GL_FIXED, 12, ptr + 1);
+ //glTexCoordPointer(2, GL_FIXED, 24, ptr + 1);
+ glColorPointer(4, GL_UNSIGNED_BYTE, 12, ptr);
+
+ glDrawArrays(GL_TRIANGLES, 0, count * 3);
+}
+
+extern "C" void drawRect(void *vp, int32_t x1, int32_t x2, int32_t y1, int32_t y2)
+{
+ x1 = (x1 << 16);
+ x2 = (x2 << 16);
+ y1 = (y1 << 16);
+ y2 = (y2 << 16);
+
+ int32_t vtx[] = {x1,y1, x1,y2, x2,y1, x2,y2};
+ static const int32_t tex[] = {0,0, 0,0x10000, 0x10000,0, 0x10000,0x10000};
+
+
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ env->mContext->setupCheck();
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ glVertexPointer(2, GL_FIXED, 8, vtx);
+ glTexCoordPointer(2, GL_FIXED, 8, tex);
+ //glColorPointer(4, GL_UNSIGNED_BYTE, 12, ptr);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+}
+
+extern "C" void pfBindTexture(void *vp, RsProgramFragment vpf, uint32_t slot, RsAllocation va)
+{
+ //LOGE("pfBindTexture %p", vpf);
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ rsi_ProgramFragmentBindTexture(env->mContext,
+ static_cast<ProgramFragment *>(vpf),
+ slot,
+ static_cast<Allocation *>(va));
+
+}
+
+extern "C" void pfBindSampler(void *vp, RsProgramFragment vpf, uint32_t slot, RsSampler vs)
+{
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ rsi_ProgramFragmentBindSampler(env->mContext,
+ static_cast<ProgramFragment *>(vpf),
+ slot,
+ static_cast<Sampler *>(vs));
+
+}
+
+extern "C" void contextBindProgramFragmentStore(void *vp, RsProgramFragmentStore pfs)
+{
+ //LOGE("contextBindProgramFragmentStore %p", pfs);
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ rsi_ContextBindProgramFragmentStore(env->mContext, pfs);
+
+}
+
+extern "C" void contextBindProgramFragment(void *vp, RsProgramFragment pf)
+{
+ //LOGE("contextBindProgramFragment %p", pf);
+ ScriptC::Env * env = static_cast<ScriptC::Env *>(vp);
+ rsi_ContextBindProgramFragment(env->mContext, pf);
+
+}
+
+
+static rsc_FunctionTable scriptCPtrTable = {
+ loadVp,
+ loadF,
+ loadI32,
+ loadU32,
+ loadEnvVec4,
+ loadEnvMatrix,
+
+ storeF,
+ storeI32,
+ storeU32,
+ storeEnvVec4,
+ storeEnvMatrix,
+
+ matrixLoadIdentity,
+ matrixLoadFloat,
+ matrixLoadMat,
+ matrixLoadRotate,
+ matrixLoadScale,
+ matrixLoadTranslate,
+ matrixLoadMultiply,
+ matrixMultiply,
+ matrixRotate,
+ matrixScale,
+ matrixTranslate,
+
+ color,
+
+ pfBindTexture,
+ pfBindSampler,
+
+ materialDiffuse,
+ materialSpecular,
+ lightPosition,
+ materialShininess,
+ uploadToTexture,
+ enable,
+ disable,
+
+ scriptRand,
+ contextBindProgramFragment,
+ contextBindProgramFragmentStore,
+
+
+ renderTriangleMesh,
+ renderTriangleMeshRange,
+
+ drawTriangleArray,
+ drawRect
+
+};
+
+
+bool ScriptC::run(Context *rsc, uint32_t launchID)
+{
+ Env e = {rsc, this};
+ return mScript(&e, &scriptCPtrTable, launchID) != 0;
+}
+
+ScriptCState::ScriptCState()
+{
+ clear();
+}
+
+ScriptCState::~ScriptCState()
+{
+ if (mAccScript) {
+ accDeleteScript(mAccScript);
+ }
+}
+
+void ScriptCState::clear()
+{
+ mConstantBufferTypes.clear();
+ mClearColor[0] = 0;
+ mClearColor[1] = 0;
+ mClearColor[2] = 0;
+ mClearColor[3] = 1;
+ mClearDepth = 1;
+ mClearStencil = 0;
+ mAccScript = NULL;
+ mScript = NULL;
+ mIsRoot = false;
+ mIsOrtho = true;
+ mScriptText = NULL;
+ mScriptTextLength = 0;
+}
+
+void ScriptCState::runCompiler()
+{
+ mAccScript = accCreateScript();
+
+ LOGE("Compiler 1");
+ const char* scriptSource[] = {mScriptText};
+ int scriptLength[] = {mScriptTextLength} ;
+ accScriptSource(mAccScript, 1, scriptSource, scriptLength);
+ accCompileScript(mAccScript);
+ accGetScriptLabel(mAccScript, "main", (ACCvoid**) &mScript);
+ LOGE("Compiler 1");
+}
+
+namespace android {
+namespace renderscript {
+
+void rsi_ScriptCBegin(Context * rsc)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->clear();
+}
+
+void rsi_ScriptCSetClearColor(Context * rsc, float r, float g, float b, float a)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mClearColor[0] = r;
+ ss->mClearColor[1] = g;
+ ss->mClearColor[2] = b;
+ ss->mClearColor[3] = a;
+}
+
+void rsi_ScriptCSetClearDepth(Context * rsc, float v)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mClearDepth = v;
+}
+
+void rsi_ScriptCSetClearStencil(Context * rsc, uint32_t v)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mClearStencil = v;
+}
+
+void rsi_ScriptCAddType(Context * rsc, RsType vt)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mConstantBufferTypes.add(static_cast<const Type *>(vt));
+}
+
+void rsi_ScriptCSetScript(Context * rsc, void* accScript, void *vp)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mAccScript = reinterpret_cast<ACCscript*>(accScript);
+ ss->mScript = reinterpret_cast<rsc_RunScript>(vp);
+}
+
+void rsi_ScriptCSetRoot(Context * rsc, bool isRoot)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mIsRoot = isRoot;
+}
+
+void rsi_ScriptCSetOrtho(Context * rsc, bool isOrtho)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mIsOrtho = isOrtho;
+}
+
+void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mScriptText = text;
+ ss->mScriptTextLength = len;
+}
+
+
+RsScript rsi_ScriptCCreate(Context * rsc)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+
+ ss->runCompiler();
+
+ ScriptC *s = new ScriptC();
+ s->mAccScript = ss->mAccScript;
+ ss->mAccScript = NULL;
+ s->mScript = ss->mScript;
+ s->mClearColor[0] = ss->mClearColor[0];
+ s->mClearColor[1] = ss->mClearColor[1];
+ s->mClearColor[2] = ss->mClearColor[2];
+ s->mClearColor[3] = ss->mClearColor[3];
+ s->mClearDepth = ss->mClearDepth;
+ s->mClearStencil = ss->mClearStencil;
+ s->mIsRoot = ss->mIsRoot;
+ s->mIsOrtho = ss->mIsOrtho;
+ s->mScriptText = ss->mScriptText;
+ s->mScriptTextLength = ss->mScriptTextLength;
+ return s;
+}
+
+}
+}
+
+
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
new file mode 100644
index 0000000..664bd6d
--- /dev/null
+++ b/libs/rs/rsScriptC.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_SCRIPT_C_H
+#define ANDROID_RS_SCRIPT_C_H
+
+#include "rsScript.h"
+
+#include "RenderScriptEnv.h"
+
+struct ACCscript;
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+
+class ScriptC : public Script
+{
+public:
+
+ ScriptC();
+ virtual ~ScriptC();
+
+
+ virtual bool run(Context *, uint32_t launchID);
+
+ const char * mScriptText;
+ uint32_t mScriptTextLength;
+
+ ACCscript* mAccScript;
+ rsc_RunScript mScript;
+
+
+ struct Env {
+ Context *mContext;
+ ScriptC *mScript;
+ };
+
+};
+
+class ScriptCState
+{
+public:
+ ScriptCState();
+ ~ScriptCState();
+
+ ACCscript* mAccScript;
+ const char * mScriptText;
+ uint32_t mScriptTextLength;
+ rsc_RunScript mScript;
+ float mClearColor[4];
+ float mClearDepth;
+ uint32_t mClearStencil;
+ bool mIsRoot;
+ bool mIsOrtho;
+
+ Vector<const Type *> mConstantBufferTypes;
+
+ void clear();
+ void runCompiler();
+};
+
+
+}
+}
+#endif
+
+
+
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
new file mode 100644
index 0000000..23c808a
--- /dev/null
+++ b/libs/rs/rsThreadIO.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+#include <utils/Log.h>
+
+#include "rsThreadIO.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+ThreadIO *android::renderscript::gIO = NULL;
+
+ThreadIO::ThreadIO()
+{
+ mToCore.init(16 * 1024);
+}
+
+ThreadIO::~ThreadIO()
+{
+}
+
+bool ThreadIO::playCoreCommands(Context *con)
+{
+ //LOGE("playCoreCommands 1");
+ uint32_t cmdID = 0;
+ uint32_t cmdSize = 0;
+ bool ret = false;
+ while(!mToCore.isEmpty()) {
+ ret = true;
+ //LOGE("playCoreCommands 2");
+ const void * data = mToCore.get(&cmdID, &cmdSize);
+ //LOGE("playCoreCommands 3 %i %i", cmdID, cmdSize);
+
+ gPlaybackFuncs[cmdID](con, data);
+ //LOGE("playCoreCommands 4");
+
+ mToCore.next();
+ //LOGE("playCoreCommands 5");
+ }
+ return ret;
+}
+
+
diff --git a/libs/rs/rsThreadIO.h b/libs/rs/rsThreadIO.h
new file mode 100644
index 0000000..ae2ffc0
--- /dev/null
+++ b/libs/rs/rsThreadIO.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_THREAD_IO_H
+#define ANDROID_RS_THREAD_IO_H
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "RenderScript.h"
+
+#include "rsLocklessFifo.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Context;
+
+class ThreadIO {
+public:
+ ThreadIO();
+ ~ThreadIO();
+
+ // Plays back commands from the client.
+ // Returns true if any commands were processed.
+ bool playCoreCommands(Context *con);
+
+
+ LocklessCommandFifo mToCore;
+ //LocklessCommandFifo mToClient;
+
+ intptr_t mToCoreRet;
+
+};
+
+extern ThreadIO *gIO;
+
+
+
+}
+}
+#endif
+
diff --git a/libs/rs/rsTriangleMesh.cpp b/libs/rs/rsTriangleMesh.cpp
new file mode 100644
index 0000000..6595ebc
--- /dev/null
+++ b/libs/rs/rsTriangleMesh.cpp
@@ -0,0 +1,299 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <utils/Log.h>
+
+TriangleMesh::TriangleMesh()
+{
+ mVertexElement = NULL;
+ mIndexElement = NULL;
+ mVertexData = NULL;
+ mIndexData = NULL;
+ mTriangleCount = 0;
+ mVertexDataSize = 0;
+ mIndexDataSize = 0;
+
+ mBufferObjects[0] = 0;
+ mBufferObjects[1] = 0;
+
+ mOffsetCoord = 0;
+ mOffsetTex = 0;
+ mOffsetNorm = 0;
+
+ mSizeCoord = 0;
+ mSizeTex = 0;
+ mSizeNorm = 0;
+
+}
+
+TriangleMesh::~TriangleMesh()
+{
+ free(mVertexData);
+ free(mIndexData);
+}
+
+
+
+TriangleMeshContext::TriangleMeshContext()
+{
+ clear();
+}
+
+TriangleMeshContext::~TriangleMeshContext()
+{
+}
+
+void TriangleMeshContext::clear()
+{
+ mVertexElement = NULL;
+ mVertexSizeBits = 0;
+ mIndexElement = NULL;
+ mIndexSizeBits = 0;
+ mTriangleCount = 0;
+ mVertexData.clear();
+ mIndexData.clear();
+}
+
+void TriangleMesh::analyzeElement()
+{
+ for (uint32_t ct=0; ct < mVertexElement->getComponentCount(); ct++) {
+ const Component *c = mVertexElement->getComponent(ct);
+
+ if (c->getKind() == Component::X) {
+ rsAssert(mSizeCoord == 0);
+ mSizeCoord = 1;
+ mOffsetCoord = ct;
+ }
+ if (c->getKind() == Component::Y) {
+ rsAssert(mSizeCoord == 1);
+ mSizeCoord = 2;
+ }
+ if (c->getKind() == Component::Z) {
+ rsAssert(mSizeCoord == 2);
+ mSizeCoord = 3;
+ }
+ if (c->getKind() == Component::W) {
+ rsAssert(mSizeCoord == 4);
+ mSizeCoord = 4;
+ }
+
+ if (c->getKind() == Component::NX) {
+ rsAssert(mSizeNorm == 0);
+ mSizeNorm = 1;
+ mOffsetNorm = ct;
+ }
+ if (c->getKind() == Component::NY) {
+ rsAssert(mSizeNorm == 1);
+ mSizeNorm = 2;
+ }
+ if (c->getKind() == Component::NZ) {
+ rsAssert(mSizeNorm == 2);
+ mSizeNorm = 3;
+ }
+
+ if (c->getKind() == Component::S) {
+ rsAssert(mSizeTex == 0);
+ mSizeTex = 1;
+ mOffsetTex = ct;
+ }
+ if (c->getKind() == Component::T) {
+ rsAssert(mSizeTex == 1);
+ mSizeTex = 2;
+ }
+ }
+ LOGE("TriangleMesh %i,%i %i,%i %i,%i", mSizeCoord, mOffsetCoord, mSizeNorm, mOffsetNorm, mSizeTex, mOffsetTex);
+
+}
+
+
+namespace android {
+namespace renderscript {
+
+void rsi_TriangleMeshBegin(Context *rsc, RsElement vertex, RsElement index)
+{
+ //LOGE("tmb %p %p", vertex, index);
+ TriangleMeshContext *tmc = &rsc->mStateTriangleMesh;
+
+ tmc->clear();
+ tmc->mVertexElement = static_cast<Element *>(vertex);
+ tmc->mVertexSizeBits = tmc->mVertexElement->getSizeBits();
+ tmc->mIndexElement = static_cast<Element *>(index);
+ tmc->mIndexSizeBits = tmc->mIndexElement->getSizeBits();
+
+ //LOGE("Element sizes %i %i", tmc->mVertexSizeBits, tmc->mIndexSizeBits);
+
+ assert(!(tmc->mVertexSizeBits & 0x7));
+ assert(!(tmc->mIndexSizeBits & 0x7));
+}
+
+void rsi_TriangleMeshAddVertex(Context *rsc, const void *data)
+{
+ TriangleMeshContext *tmc = &rsc->mStateTriangleMesh;
+
+ // todo: Make this efficient.
+ for (uint32_t ct = 0; (ct * 8) < tmc->mVertexSizeBits; ct++) {
+ tmc->mVertexData.add(static_cast<const uint8_t *>(data) [ct]);
+ }
+}
+
+void rsi_TriangleMeshAddTriangle(Context *rsc, uint32_t idx1, uint32_t idx2, uint32_t idx3)
+{
+ TriangleMeshContext *tmc = &rsc->mStateTriangleMesh;
+
+ // todo: Make this efficient.
+ switch(tmc->mIndexSizeBits) {
+ case 16:
+ tmc->mIndexData.add(idx1);
+ tmc->mIndexData.add(idx2);
+ tmc->mIndexData.add(idx3);
+ break;
+ default:
+ assert(0);
+ }
+
+ tmc->mTriangleCount++;
+}
+
+RsTriangleMesh rsi_TriangleMeshCreate(Context *rsc)
+{
+ TriangleMeshContext *tmc = &rsc->mStateTriangleMesh;
+
+ TriangleMesh * tm = new TriangleMesh();
+ if (!tm) {
+ LOGE("rsTriangleMeshCreate: Error OUT OF MEMORY");
+ // error
+ return 0;
+ }
+
+ tm->mTriangleCount = tmc->mTriangleCount;
+ tm->mIndexDataSize = tmc->mIndexData.size() * tmc->mIndexSizeBits >> 3;
+ tm->mVertexDataSize = tmc->mVertexData.size();
+ tm->mIndexElement = tmc->mIndexElement;
+ tm->mVertexElement = tmc->mVertexElement;
+
+ tm->mIndexData = malloc(tm->mIndexDataSize);
+ tm->mVertexData = malloc(tm->mVertexDataSize);
+ if (!tm->mIndexData || !tm->mVertexData) {
+ LOGE("rsTriangleMeshCreate: Error OUT OF MEMORY");
+ delete tm;
+ return 0;
+ }
+
+ LOGE("Create mesh, triangleCount %i", tm->mTriangleCount);
+
+ memcpy(tm->mVertexData, tmc->mVertexData.array(), tm->mVertexDataSize);
+ memcpy(tm->mIndexData, tmc->mIndexData.array(), tm->mIndexDataSize);
+ tm->analyzeElement();
+
+ return tm;
+}
+
+void rsi_TriangleMeshDestroy(Context *rsc, RsTriangleMesh vtm)
+{
+ TriangleMeshContext *tmc = &rsc->mStateTriangleMesh;
+ TriangleMesh * tm = static_cast<TriangleMesh *>(vtm);
+
+ free(tm->mIndexData);
+ free(tm->mVertexData);
+ delete tm;
+}
+
+
+
+void rsi_TriangleMeshRenderRange(Context *rsc, RsTriangleMesh vtm, uint32_t first, uint32_t count)
+{
+ TriangleMesh * tm = static_cast<TriangleMesh *>(vtm);
+
+ rsc->setupCheck();
+
+ //LOGE("1 %p ", vtm);
+ //LOGE("1.1 %p %p", tm->mVertexData, tm->mIndexData);
+ if (!tm->mBufferObjects[0]) {
+ glGenBuffers(2, &tm->mBufferObjects[0]);
+
+ glBindBuffer(GL_ARRAY_BUFFER, tm->mBufferObjects[0]);
+ glBufferData(GL_ARRAY_BUFFER, tm->mVertexDataSize, tm->mVertexData, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, tm->mIndexDataSize, tm->mIndexData, GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+
+ //LOGE("1.2");
+ if (first >= tm->mTriangleCount) {
+ return;
+ }
+ if (count >= (tm->mTriangleCount - first)) {
+ count = tm->mTriangleCount - first;
+ }
+ if (!count) {
+ return;
+ }
+
+ const float *f = (const float *)tm->mVertexData;
+
+ //LOGE("2");
+ glBindBuffer(GL_ARRAY_BUFFER, tm->mBufferObjects[0]);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(tm->mSizeCoord,
+ GL_FLOAT,
+ tm->mVertexElement->getSizeBytes(),
+ (void *)tm->mVertexElement->getComponentOffsetBytes(tm->mOffsetCoord));
+
+ if (tm->mSizeTex) {
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(tm->mSizeTex,
+ GL_FLOAT,
+ tm->mVertexElement->getSizeBytes(),
+ (void *)tm->mVertexElement->getComponentOffsetBytes(tm->mOffsetTex));
+ } else {
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ }
+
+ if (tm->mSizeNorm) {
+ glEnableClientState(GL_NORMAL_ARRAY);
+ glNormalPointer(GL_FLOAT,
+ tm->mVertexElement->getSizeBytes(),
+ (void *)tm->mVertexElement->getComponentOffsetBytes(tm->mOffsetNorm));
+ } else {
+ glDisableClientState(GL_NORMAL_ARRAY);
+ }
+
+ glDrawElements(GL_TRIANGLES, count * 3, GL_UNSIGNED_SHORT, (GLvoid *)(first * 3 * 2));
+
+ //LOGE("4");
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+}
+
+void rsi_TriangleMeshRender(Context *rsc, RsTriangleMesh vtm)
+{
+ rsi_TriangleMeshRenderRange(rsc, vtm, 0, 0xffffff);
+}
+
+}}
diff --git a/libs/rs/rsTriangleMesh.h b/libs/rs/rsTriangleMesh.h
new file mode 100644
index 0000000..67f964f
--- /dev/null
+++ b/libs/rs/rsTriangleMesh.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_TRIANGLE_MESH_H
+#define ANDROID_RS_TRIANGLE_MESH_H
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <math.h>
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <utils/Vector.h>
+
+#include "RenderScript.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+// An element is a group of Components that occupies one cell in a structure.
+class TriangleMesh
+{
+public:
+ TriangleMesh();
+ ~TriangleMesh();
+
+ const Element * mVertexElement;
+ const Element * mIndexElement;
+
+ void * mVertexData;
+ void * mIndexData;
+
+ size_t mVertexDataSize;
+ size_t mIndexDataSize;
+ uint32_t mTriangleCount;
+
+ size_t mOffsetCoord;
+ size_t mOffsetTex;
+ size_t mOffsetNorm;
+
+ size_t mSizeCoord;
+ size_t mSizeTex;
+ size_t mSizeNorm;
+
+ // GL buffer info
+ GLuint mBufferObjects[2];
+
+ void analyzeElement();
+protected:
+};
+
+class TriangleMeshContext
+{
+public:
+ TriangleMeshContext();
+ ~TriangleMeshContext();
+
+ const Element * mVertexElement;
+ const Element * mIndexElement;
+ size_t mVertexSizeBits;
+ size_t mIndexSizeBits;
+
+ Vector<uint8_t> mVertexData;
+ Vector<uint16_t> mIndexData;
+
+ uint32_t mTriangleCount;
+
+ void clear();
+};
+
+
+}
+}
+#endif //ANDROID_RS_TRIANGLE_MESH_H
+
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
new file mode 100644
index 0000000..6b99820
--- /dev/null
+++ b/libs/rs/rsType.cpp
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+Type::Type()
+{
+ mLODs = 0;
+ mLODCount = 0;
+ clear();
+}
+
+Type::~Type()
+{
+ if (mLODs) {
+ delete [] mLODs;
+ }
+}
+
+void Type::clear()
+{
+ if (mLODs) {
+ delete [] mLODs;
+ mLODs = NULL;
+ }
+ mDimX = 0;
+ mDimY = 0;
+ mDimZ = 0;
+ mDimLOD = 0;
+ mFaces = false;
+ mElement.clear();
+}
+
+TypeState::TypeState()
+{
+}
+
+TypeState::~TypeState()
+{
+}
+
+size_t Type::getOffsetForFace(uint32_t face) const
+{
+ rsAssert(mFaces);
+ return 0;
+}
+
+void Type::compute()
+{
+ //LOGE("compute");
+ uint32_t oldLODCount = mLODCount;
+ if (mDimLOD) {
+ uint32_t l2x = rsFindHighBit(mDimX) + 1;
+ uint32_t l2y = rsFindHighBit(mDimY) + 1;
+ uint32_t l2z = rsFindHighBit(mDimZ) + 1;
+
+ mLODCount = rsMax(l2x, l2y);
+ mLODCount = rsMax(mLODCount, l2z);
+ } else {
+ mLODCount = 1;
+ }
+ if (mLODCount != oldLODCount) {
+ delete [] mLODs;
+ mLODs = new LOD[mLODCount];
+ }
+
+ //LOGE("xyz %i %i %i", mDimX, mDimY, mDimZ);
+ //LOGE("mips %i", mLODCount);
+ //LOGE("e size %i", mElement->getSizeBytes());
+ uint32_t tx = mDimX;
+ uint32_t ty = mDimY;
+ uint32_t tz = mDimZ;
+ size_t offset = 0;
+ for (uint32_t lod=0; lod < mLODCount; lod++) {
+ mLODs[lod].mX = tx;
+ mLODs[lod].mY = ty;
+ mLODs[lod].mZ = tz;
+ mLODs[lod].mOffset = offset;
+ //LOGE("txyz %i %i %i", tx, ty, tz);
+ offset += tx * rsMax(ty, 1u) * rsMax(tz, 1u) * mElement->getSizeBytes();
+ tx >>= 1;
+ ty >>= 1;
+ tz >>= 1;
+ }
+
+ //LOGE("size %i", offset);
+
+ // At this point the offset is the size of a mipmap chain;
+ mMipChainSizeBytes = offset;
+
+ if (mFaces) {
+ offset *= 6;
+ }
+ mTotalSizeBytes = offset;
+
+}
+
+uint32_t Type::getLODOffset(uint32_t lod, uint32_t x) const
+{
+ uint32_t offset = mLODs[lod].mOffset;
+ offset += x * mElement->getSizeBytes();
+ return offset;
+}
+
+uint32_t Type::getLODOffset(uint32_t lod, uint32_t x, uint32_t y) const
+{
+ uint32_t offset = mLODs[lod].mOffset;
+ offset += (x + y * mLODs[lod].mX) * mElement->getSizeBytes();
+ return offset;
+}
+
+uint32_t Type::getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) const
+{
+ uint32_t offset = mLODs[lod].mOffset;
+ offset += (x + y*mLODs[lod].mX + z*mLODs[lod].mX*mLODs[lod].mY) * mElement->getSizeBytes();
+ return offset;
+}
+
+
+//////////////////////////////////////////////////
+//
+namespace android {
+namespace renderscript {
+
+void rsi_TypeBegin(Context *rsc, RsElement vse)
+{
+ TypeState * stc = &rsc->mStateType;
+
+ stc->mX = 0;
+ stc->mY = 0;
+ stc->mZ = 0;
+ stc->mLOD = false;
+ stc->mFaces = false;
+ stc->mElement.set(static_cast<const Element *>(vse));
+}
+
+void rsi_TypeAdd(Context *rsc, RsDimension dim, size_t value)
+{
+ TypeState * stc = &rsc->mStateType;
+
+ if (dim < 0) {
+ //error
+ return;
+ }
+
+
+ switch (dim) {
+ case RS_DIMENSION_X:
+ stc->mX = value;
+ return;
+ case RS_DIMENSION_Y:
+ stc->mY = value;
+ return;
+ case RS_DIMENSION_Z:
+ stc->mZ = value;
+ return;
+ case RS_DIMENSION_FACE:
+ stc->mFaces = (value != 0);
+ return;
+ case RS_DIMENSION_LOD:
+ stc->mLOD = (value != 0);
+ return;
+ default:
+ break;
+ }
+
+
+ int32_t arrayNum = dim - RS_DIMENSION_ARRAY_0;
+ if ((dim < 0) || (dim > RS_DIMENSION_MAX)) {
+ LOGE("rsTypeAdd: Bad dimension");
+ //error
+ return;
+ }
+
+ // todo: implement array support
+
+}
+
+RsType rsi_TypeCreate(Context *rsc)
+{
+ TypeState * stc = &rsc->mStateType;
+
+ Type * st = new Type();
+ st->setDimX(stc->mX);
+ st->setDimY(stc->mY);
+ st->setDimZ(stc->mZ);
+ st->setElement(stc->mElement.get());
+ st->setDimLOD(stc->mLOD);
+ st->setDimFaces(stc->mFaces);
+ st->compute();
+
+ stc->mAllTypes.add(st);
+
+ return st;
+}
+
+void rsi_TypeDestroy(Context *rsc, RsType vst)
+{
+ TypeState * stc = &rsc->mStateType;
+ Type * st = static_cast<Type *>(vst);
+
+ for (size_t ct = 0; ct < stc->mAllTypes.size(); ct++) {
+ if (stc->mAllTypes[ct] == st) {
+ stc->mAllTypes.removeAt(ct);
+ break;
+ }
+ }
+ delete st;
+}
+
+}
+}
+
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
new file mode 100644
index 0000000..a717893
--- /dev/null
+++ b/libs/rs/rsType.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_STRUCTURED_TYPE_H
+#define ANDROID_STRUCTURED_TYPE_H
+
+#include "rsElement.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+class Type : public ObjectBase
+{
+public:
+ Type();
+ virtual ~Type();
+
+ Type * createTex2D(const Element *, size_t w, size_t h, bool mip);
+
+
+ size_t getOffsetForFace(uint32_t face) const;
+
+ size_t getSizeBytes() const {return mTotalSizeBytes;}
+ size_t getElementSizeBytes() const {return mElement->getSizeBytes();}
+ const Element * getElement() const {return mElement.get();}
+
+ uint32_t getDimX() const {return mDimX;}
+ uint32_t getDimY() const {return mDimY;}
+ uint32_t getDimZ() const {return mDimZ;}
+ uint32_t getDimLOD() const {return mDimLOD;}
+ bool getDimFaces() const {return mFaces;}
+
+ uint32_t getLODDimX(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mX;}
+ uint32_t getLODDimY(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mY;}
+ uint32_t getLODDimZ(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mZ;}
+ uint32_t getLODOffset(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mOffset;}
+
+ uint32_t getLODOffset(uint32_t lod, uint32_t x) const;
+ uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y) const;
+ uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) const;
+
+ uint32_t getLODCount() const {return mLODCount;}
+
+
+ void setElement(const Element *e) {mElement.set(e);}
+ void setDimX(uint32_t v) {mDimX = v;}
+ void setDimY(uint32_t v) {mDimY = v;}
+ void setDimZ(uint32_t v) {mDimZ = v;}
+ void setDimFaces(bool v) {mFaces = v;}
+ void setDimLOD(bool v) {mDimLOD = v;}
+
+ void clear();
+ void compute();
+
+
+protected:
+ struct LOD {
+ size_t mX;
+ size_t mY;
+ size_t mZ;
+ size_t mOffset;
+ };
+
+ void makeLODTable();
+
+ // Internal structure from most to least significant.
+ // * Array dimensions
+ // * Faces
+ // * Mipmaps
+ // * xyz
+
+ ObjectBaseRef<const Element> mElement;
+
+ // Size of the structure in the various dimensions. A missing Dimension is
+ // specified as a 0 and not a 1.
+ size_t mDimX;
+ size_t mDimY;
+ size_t mDimZ;
+ bool mDimLOD;
+ bool mFaces;
+
+ // A list of array dimensions. The count is the number of array dimensions and the
+ // sizes is a per array size.
+ //Vector<size_t> mDimArraysSizes;
+
+ // count of mipmap levels, 0 indicates no mipmapping
+
+ size_t mMipChainSizeBytes;
+ size_t mTotalSizeBytes;
+ LOD *mLODs;
+ uint32_t mLODCount;
+
+private:
+ Type(const Type &);
+};
+
+
+class TypeState {
+public:
+ TypeState();
+ ~TypeState();
+
+ Vector<Type *> mAllTypes;
+
+ size_t mX;
+ size_t mY;
+ size_t mZ;
+ uint32_t mLOD;
+ bool mFaces;
+ ObjectBaseRef<const Element> mElement;
+
+
+
+};
+
+
+}
+}
+#endif //ANDROID_STRUCTURED_TYPE
diff --git a/libs/rs/rsUtils.h b/libs/rs/rsUtils.h
new file mode 100644
index 0000000..5a43fb3
--- /dev/null
+++ b/libs/rs/rsUtils.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_UTILS_H
+#define ANDROID_RS_UTILS_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+namespace android {
+namespace renderscript {
+
+#if 1
+#define rsAssert(v) do {if(!(v)) LOGE("rsAssert failed: %s, in %s at %i", #v, __FILE__, __LINE__);} while(0)
+#else
+#define rsAssert(v) while(0)
+#endif
+
+template<typename T>
+T rsMin(T in1, T in2)
+{
+ if (in1 > in2) {
+ return in2;
+ }
+ return in1;
+}
+
+template<typename T>
+T rsMax(T in1, T in2)
+{
+ if (in1 < in2) {
+ return in2;
+ }
+ return in1;
+}
+
+template<typename T>
+T rsFindHighBit(T val)
+{
+ uint32_t bit = 0;
+ while(val > 1) {
+ bit++;
+ val>>=1;
+ }
+ return bit;
+}
+
+template<typename T>
+bool rsIsPow2(T val)
+{
+ return (val & (val-1)) == 0;
+}
+
+template<typename T>
+T rsHigherPow2(T v)
+{
+ if (rsIsPow2(v)) {
+ return v;
+ }
+ return 1 << (rsFindHighBit(v) + 1);
+}
+
+template<typename T>
+T rsLowerPow2(T v)
+{
+ if (rsIsPow2(v)) {
+ return v;
+ }
+ return 1 << rsFindHighBit(v);
+}
+
+
+static inline uint16_t rs888to565(uint32_t r, uint32_t g, uint32_t b)
+{
+ uint16_t t = 0;
+ t |= b >> 3;
+ t |= (g >> 2) << 5;
+ t |= (r >> 3) << 11;
+ return t;
+}
+
+static inline uint16_t rsBoxFilter565(uint16_t i1, uint16_t i2, uint16_t i3, uint16_t i4)
+{
+ uint32_t r = ((i1 & 0x1f) + (i2 & 0x1f) + (i3 & 0x1f) + (i4 & 0x1f));
+ uint32_t g = ((i1 >> 5) & 0x3f) + ((i2 >> 5) & 0x3f) + ((i3 >> 5) & 0x3f) + ((i4 >> 5) & 0x3f);
+ uint32_t b = ((i1 >> 11) + (i2 >> 11) + (i3 >> 11) + (i4 >> 11));
+ return (r >> 2) | ((g >> 2) << 5) | ((b >> 2) << 11);
+}
+
+static inline uint32_t rsBoxFilter8888(uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4)
+{
+ uint32_t r = (i1 & 0xff) + (i2 & 0xff) + (i3 & 0xff) + (i4 & 0xff);
+ uint32_t g = ((i1 >> 8) & 0xff) + ((i2 >> 8) & 0xff) + ((i3 >> 8) & 0xff) + ((i4 >> 8) & 0xff);
+ uint32_t b = ((i1 >> 16) & 0xff) + ((i2 >> 16) & 0xff) + ((i3 >> 16) & 0xff) + ((i4 >> 16) & 0xff);
+ uint32_t a = ((i1 >> 24) & 0xff) + ((i2 >> 24) & 0xff) + ((i3 >> 24) & 0xff) + ((i4 >> 24) & 0xff);
+ return (r >> 2) | ((g >> 2) << 8) | ((b >> 2) << 16) | ((a >> 2) << 24);
+}
+
+
+
+}
+}
+
+#endif //ANDROID_RS_OBJECT_BASE_H
+
+
diff --git a/libs/rs/rsgApi.cpp.rsg b/libs/rs/rsgApi.cpp.rsg
new file mode 100644
index 0000000..0cfbf08
--- /dev/null
+++ b/libs/rs/rsgApi.cpp.rsg
@@ -0,0 +1 @@
+2
diff --git a/libs/rs/rsgApiFuncDecl.h.rsg b/libs/rs/rsgApiFuncDecl.h.rsg
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/libs/rs/rsgApiFuncDecl.h.rsg
@@ -0,0 +1 @@
+1
diff --git a/libs/rs/rsgApiReplay.cpp.rsg b/libs/rs/rsgApiReplay.cpp.rsg
new file mode 100644
index 0000000..00750ed
--- /dev/null
+++ b/libs/rs/rsgApiReplay.cpp.rsg
@@ -0,0 +1 @@
+3
diff --git a/libs/rs/rsgApiStructs.h.rsg b/libs/rs/rsgApiStructs.h.rsg
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/libs/rs/rsgApiStructs.h.rsg
@@ -0,0 +1 @@
+0
diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c
new file mode 100644
index 0000000..a4d659d
--- /dev/null
+++ b/libs/rs/rsg_generator.c
@@ -0,0 +1,291 @@
+
+
+#include "lex.yy.c"
+
+void printFileHeader(FILE *f)
+{
+ fprintf(f, "/*\n");
+ fprintf(f, " * Copyright (C) 2009 The Android Open Source Project\n");
+ fprintf(f, " *\n");
+ fprintf(f, " * Licensed under the Apache License, Version 2.0 (the \"License\");\n");
+ fprintf(f, " * you may not use this file except in compliance with the License.\n");
+ fprintf(f, " * You may obtain a copy of the License at\n");
+ fprintf(f, " *\n");
+ fprintf(f, " * http://www.apache.org/licenses/LICENSE-2.0\n");
+ fprintf(f, " *\n");
+ fprintf(f, " * Unless required by applicable law or agreed to in writing, software\n");
+ fprintf(f, " * distributed under the License is distributed on an \"AS IS\" BASIS,\n");
+ fprintf(f, " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n");
+ fprintf(f, " * See the License for the specific language governing permissions and\n");
+ fprintf(f, " * limitations under the License.\n");
+ fprintf(f, " */\n\n");
+}
+
+void printVarType(FILE *f, const VarType *vt)
+{
+ int ct;
+ if (vt->isConst) {
+ fprintf(f, "const ");
+ }
+
+ switch(vt->type) {
+ case 0:
+ fprintf(f, "void");
+ break;
+ case 1:
+ fprintf(f, "int%i_t", vt->bits);
+ break;
+ case 2:
+ fprintf(f, "uint%i_t", vt->bits);
+ break;
+ case 3:
+ if (vt->bits == 32)
+ fprintf(f, "float");
+ else
+ fprintf(f, "double");
+ break;
+ case 4:
+ fprintf(f, "%s", vt->typename);
+ break;
+ }
+
+ if(vt->ptrLevel) {
+ fprintf(f, " ");
+ for(ct=0; ct < vt->ptrLevel; ct++) {
+ fprintf(f, "*");
+ }
+ }
+
+ if(vt->name[0]) {
+ fprintf(f, " %s", vt->name);
+ }
+}
+
+void printArgList(FILE *f, const ApiEntry * api, int assumePrevious)
+{
+ int ct;
+ for(ct=0; ct < api->paramCount; ct++) {
+ if (ct || assumePrevious) {
+ fprintf(f, ", ");
+ }
+ printVarType(f, &api->params[ct]);
+ }
+}
+
+void printStructures(FILE *f)
+{
+ int ct;
+ int ct2;
+
+ for(ct=0; ct < apiCount; ct++) {
+ fprintf(f, "typedef struct RS_CMD_%s_rec RS_CMD_%s;\n", apis[ct].name, apis[ct].name);
+ }
+ fprintf(f, "\n");
+
+ for(ct=0; ct < apiCount; ct++) {
+ const ApiEntry * api = &apis[ct];
+ fprintf(f, "#define RS_CMD_ID_%s %i\n", api->name, ct+1);
+ fprintf(f, "struct RS_CMD_%s_rec {\n", api->name);
+ //fprintf(f, " RsCommandHeader _hdr;\n");
+
+ for(ct2=0; ct2 < api->paramCount; ct2++) {
+ fprintf(f, " ");
+ printVarType(f, &api->params[ct2]);
+ fprintf(f, ";\n");
+ }
+ fprintf(f, "};\n\n");
+ }
+}
+
+void printFuncDecl(FILE *f, const ApiEntry *api, const char *prefix, int addContext)
+{
+ printVarType(f, &api->ret);
+ fprintf(f, " %s%s (", prefix, api->name);
+ if (addContext) {
+ fprintf(f, "Context *");
+ }
+ printArgList(f, api, addContext);
+ fprintf(f, ")");
+}
+
+void printFuncDecls(FILE *f, const char *prefix, int addContext)
+{
+ int ct;
+ for(ct=0; ct < apiCount; ct++) {
+ printFuncDecl(f, &apis[ct], prefix, addContext);
+ fprintf(f, ";\n");
+ }
+ fprintf(f, "\n\n");
+}
+
+void printPlaybackFuncs(FILE *f, const char *prefix)
+{
+ int ct;
+ for(ct=0; ct < apiCount; ct++) {
+ fprintf(f, "void %s%s (Context *, const void *);\n", prefix, apis[ct].name);
+ }
+}
+
+void printApiCpp(FILE *f)
+{
+ int ct;
+ int ct2;
+
+ fprintf(f, "#include \"rsDevice.h\"\n");
+ fprintf(f, "#include \"rsContext.h\"\n");
+ fprintf(f, "#include \"rsThreadIO.h\"\n");
+ //fprintf(f, "#include \"rsgApiStructs.h\"\n");
+ fprintf(f, "#include \"rsgApiFuncDecl.h\"\n");
+ fprintf(f, "\n");
+ fprintf(f, "using namespace android;\n");
+ fprintf(f, "using namespace android::renderscript;\n");
+ fprintf(f, "\n");
+
+ for(ct=0; ct < apiCount; ct++) {
+ int needFlush = 0;
+ const ApiEntry * api = &apis[ct];
+
+ printFuncDecl(f, api, "rs", 0);
+ fprintf(f, "\n{\n");
+ fprintf(f, " ThreadIO *io = gIO;\n");
+ //fprintf(f, " LOGE(\"add command %s\\n\");\n", api->name);
+ fprintf(f, " RS_CMD_%s *cmd = static_cast<RS_CMD_%s *>(io->mToCore.reserve(sizeof(RS_CMD_%s)));\n", api->name, api->name, api->name);
+ fprintf(f, " uint32_t size = sizeof(RS_CMD_%s);\n", api->name);
+
+ for(ct2=0; ct2 < api->paramCount; ct2++) {
+ const VarType *vt = &api->params[ct2];
+ needFlush += vt->ptrLevel;
+ fprintf(f, " cmd->%s = %s;\n", vt->name, vt->name);
+ }
+ if (api->ret.typename[0]) {
+ needFlush = 1;
+ }
+
+ fprintf(f, " io->mToCore.commit");
+ if (needFlush) {
+ fprintf(f, "Sync");
+ }
+ fprintf(f, "(RS_CMD_ID_%s, size);\n", api->name);
+
+ if (api->ret.typename[0]) {
+ fprintf(f, " return reinterpret_cast<");
+ printVarType(f, &api->ret);
+ fprintf(f, ">(io->mToCoreRet);\n");
+ }
+ fprintf(f, "};\n\n");
+ }
+}
+
+void printPlaybackCpp(FILE *f)
+{
+ int ct;
+ int ct2;
+
+ fprintf(f, "#include \"rsDevice.h\"\n");
+ fprintf(f, "#include \"rsContext.h\"\n");
+ fprintf(f, "#include \"rsThreadIO.h\"\n");
+ //fprintf(f, "#include \"rsgApiStructs.h\"\n");
+ fprintf(f, "#include \"rsgApiFuncDecl.h\"\n");
+ fprintf(f, "\n");
+ fprintf(f, "namespace android {\n");
+ fprintf(f, "namespace renderscript {\n");
+ fprintf(f, "\n");
+
+ for(ct=0; ct < apiCount; ct++) {
+ const ApiEntry * api = &apis[ct];
+
+ fprintf(f, "void rsp_%s(Context *con, const void *vp)\n", api->name);
+ fprintf(f, "{\n");
+ //fprintf(f, " LOGE(\"play command %s\\n\");\n", api->name);
+ fprintf(f, " const RS_CMD_%s *cmd = static_cast<const RS_CMD_%s *>(vp);\n", api->name, api->name);
+ fprintf(f, " ");
+ if (api->ret.typename[0]) {
+ fprintf(f, "gIO->mToCoreRet = (intptr_t)");
+ }
+ fprintf(f, "rsi_%s(con", api->name);
+ for(ct2=0; ct2 < api->paramCount; ct2++) {
+ const VarType *vt = &api->params[ct2];
+ fprintf(f, ",");
+ fprintf(f, "\n cmd->%s", vt->name);
+ }
+ fprintf(f, ");\n");
+
+ fprintf(f, "};\n\n");
+ }
+
+ fprintf(f, "RsPlaybackFunc gPlaybackFuncs[] = {\n");
+ fprintf(f, " NULL,\n");
+ for(ct=0; ct < apiCount; ct++) {
+ fprintf(f, " %s%s,\n", "rsp_", apis[ct].name);
+ }
+ fprintf(f, "};\n");
+
+ fprintf(f, "};\n");
+ fprintf(f, "};\n");
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 3) {
+ fprintf(stderr, "usage: %s commandFile outFile\n", argv[0]);
+ return 1;
+ }
+ const char* rsgFile = argv[1];
+ const char* outFile = argv[2];
+ FILE* input = fopen(rsgFile, "r");
+
+ char choice = fgetc(input);
+ fclose(input);
+
+ if (choice < '0' || choice > '3') {
+ fprintf(stderr, "Uknown command: \'%c\'\n", choice);
+ return -2;
+ }
+
+ yylex();
+ // printf("# of lines = %d\n", num_lines);
+
+ FILE *f = fopen(outFile, "w");
+
+ printFileHeader(f);
+ switch(choice) {
+ case '0': // rsgApiStructs.h
+ {
+ fprintf(f, "\n");
+ fprintf(f, "#include \"rsContext.h\"\n");
+ fprintf(f, "\n");
+ fprintf(f, "namespace android {\n");
+ fprintf(f, "namespace renderscript {\n");
+ printStructures(f);
+ printFuncDecls(f, "rsi_", 1);
+ printPlaybackFuncs(f, "rsp_");
+ fprintf(f, "\n\ntypedef void (*RsPlaybackFunc)(Context *, const void *);\n");
+ fprintf(f, "extern RsPlaybackFunc gPlaybackFuncs[];\n");
+
+ fprintf(f, "}\n");
+ fprintf(f, "}\n");
+ }
+ break;
+
+ case '1': // rsgApiFuncDecl.h
+ {
+ printFuncDecls(f, "rs", 0);
+ }
+ break;
+
+ case '2': // rsgApi.cpp
+ {
+ printApiCpp(f);
+ }
+ break;
+
+ case '3': // rsgApiReplay.cpp
+ {
+ printFileHeader(f);
+ printPlaybackCpp(f);
+ }
+ break;
+ }
+ fclose(f);
+ return 0;
+}
diff --git a/libs/rs/spec.lex b/libs/rs/spec.lex
new file mode 100644
index 0000000..0f8e9ab
--- /dev/null
+++ b/libs/rs/spec.lex
@@ -0,0 +1,171 @@
+%option stack
+
+%x comment
+%x api_entry
+%x api_entry2
+%x api_entry_param
+%x var_type
+
+DIGIT [0-9]
+ID [a-zA-Z_][a-zA-Z0-9_]*
+
+
+ int num_lines = 0;
+
+ typedef struct {
+ int isConst;
+ int type;
+ int bits;
+ int ptrLevel;
+ char name[256];
+ char typename[256];
+ } VarType;
+
+ VarType *currType = 0;
+
+ typedef struct {
+ char name[256];
+ int sync;
+ int paramCount;
+ VarType ret;
+ VarType params[16];
+ } ApiEntry;
+
+ ApiEntry apis[128];
+ int apiCount = 0;
+
+ int typeNextState;
+
+%%
+
+"/*" BEGIN(comment);
+<comment>[^*\n]* /* eat anything that's not a '*' */
+<comment>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
+<comment>\n ++num_lines;
+<comment>"*"+"/" BEGIN(INITIAL);
+
+<*>" " //printf("found ' '\n");
+<*>"\n" ++num_lines; //printf("found lf \n");
+
+{ID} {
+ memset(&apis[apiCount], 0, sizeof(ApiEntry));
+ memcpy(apis[apiCount].name, yytext, yyleng);
+ BEGIN(api_entry);
+ }
+
+<api_entry>"{" {
+ BEGIN(api_entry2);
+ }
+
+<api_entry2>"sync" {
+ apis[apiCount].sync = 1;
+ }
+
+<api_entry2>"ret" {
+ currType = &apis[apiCount].ret;
+ typeNextState = api_entry2;
+ BEGIN(var_type);
+ }
+
+<api_entry2>"param" {
+ currType = &apis[apiCount].params[apis[apiCount].paramCount];
+ apis[apiCount].paramCount++;
+ typeNextState = api_entry_param;
+ BEGIN(var_type);
+ }
+
+<var_type>"const" {
+ currType->isConst = 1;
+ }
+
+<var_type>"i8" {
+ currType->type = 1;
+ currType->bits = 8;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"i16" {
+ currType->type = 1;
+ currType->bits = 16;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"i32" {
+ currType->type = 1;
+ currType->bits = 32;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"i64" {
+ currType->type = 1;
+ currType->bits = 64;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"u8" {
+ currType->type = 2;
+ currType->bits = 8;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"u16" {
+ currType->type = 2;
+ currType->bits = 16;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"u32" {
+ currType->type = 2;
+ currType->bits = 32;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"u64" {
+ currType->type = 2;
+ currType->bits = 64;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"f" {
+ currType->type = 3;
+ currType->bits = 32;
+ BEGIN(typeNextState);
+ }
+
+<var_type>"d" {
+ currType->type = 3;
+ currType->bits = 64;
+ BEGIN(typeNextState);
+ }
+
+<var_type>{ID} {
+ currType->type = 4;
+ currType->bits = 32;
+ memcpy(currType->typename, yytext, yyleng);
+ BEGIN(typeNextState);
+ }
+
+<api_entry_param>"*" {
+ currType->ptrLevel ++;
+ }
+
+<api_entry_param>{ID} {
+ memcpy(currType->name, yytext, yyleng);
+ BEGIN(api_entry2);
+ }
+
+
+<api_entry2>"}" {
+ apiCount++;
+ BEGIN(INITIAL);
+ }
+
+
+%%
+
+
+int yywrap()
+{
+ return 1;
+}
+
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
index 9272983..a5698f2 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -33,6 +33,7 @@ endif
LOCAL_SHARED_LIBRARIES := \
libhardware \
libutils \
+ libbinder \
libcutils \
libui \
libcorecg \
diff --git a/libs/surfaceflinger/GPUHardware/GPUHardware.cpp b/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
index 7168bf2..2de628b 100644
--- a/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
+++ b/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
@@ -30,12 +30,12 @@
#include <cutils/log.h>
#include <cutils/properties.h>
-#include <utils/IBinder.h>
-#include <utils/MemoryDealer.h>
-#include <utils/MemoryBase.h>
-#include <utils/MemoryHeapPmem.h>
-#include <utils/MemoryHeapBase.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IBinder.h>
+#include <binder/MemoryDealer.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapPmem.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/IPCThreadState.h>
#include <utils/StopWatch.h>
#include <ui/ISurfaceComposer.h>
diff --git a/libs/surfaceflinger/LayerBitmap.cpp b/libs/surfaceflinger/LayerBitmap.cpp
index 397ddc8..eb3c3e5 100644
--- a/libs/surfaceflinger/LayerBitmap.cpp
+++ b/libs/surfaceflinger/LayerBitmap.cpp
@@ -23,8 +23,8 @@
#include <cutils/memory.h>
#include <utils/Errors.h>
#include <utils/Log.h>
-#include <utils/MemoryDealer.h>
-#include <utils/IMemory.h>
+#include <binder/MemoryDealer.h>
+#include <binder/IMemory.h>
#include <ui/PixelFormat.h>
#include <pixelflinger/pixelflinger.h>
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index 00fab70..bac544a 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -25,8 +25,8 @@
#include <utils/Log.h>
#include <utils/StopWatch.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <ui/PixelFormat.h>
#include <ui/EGLDisplaySurface.h>
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index 2dc77f1..f74d6a1 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -20,7 +20,7 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <private/ui/LayerState.h>
#include <EGL/eglnatives.h>
diff --git a/libs/surfaceflinger/LayerOrientationAnim.h b/libs/surfaceflinger/LayerOrientationAnim.h
index 365c6ae..e86156d 100644
--- a/libs/surfaceflinger/LayerOrientationAnim.h
+++ b/libs/surfaceflinger/LayerOrientationAnim.h
@@ -20,7 +20,7 @@
#include <stdint.h>
#include <sys/types.h>
#include <utils/threads.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include "LayerBase.h"
#include "LayerBitmap.h"
diff --git a/libs/surfaceflinger/LayerOrientationAnimRotate.h b/libs/surfaceflinger/LayerOrientationAnimRotate.h
index 5fbbd42..3296f45 100644
--- a/libs/surfaceflinger/LayerOrientationAnimRotate.h
+++ b/libs/surfaceflinger/LayerOrientationAnimRotate.h
@@ -20,7 +20,7 @@
#include <stdint.h>
#include <sys/types.h>
#include <utils/threads.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include "LayerBase.h"
#include "LayerBitmap.h"
diff --git a/libs/surfaceflinger/LayerScreenshot.cpp b/libs/surfaceflinger/LayerScreenshot.cpp
new file mode 100644
index 0000000..fb7b585
--- /dev/null
+++ b/libs/surfaceflinger/LayerScreenshot.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <core/SkBitmap.h>
+
+#include <ui/EGLDisplaySurface.h>
+
+#include "LayerBase.h"
+#include "LayerScreenshot.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerScreenshot::typeInfo = LayerBase::typeInfo | 0x20;
+const char* const LayerScreenshot::typeID = "LayerScreenshot";
+
+// ---------------------------------------------------------------------------
+
+LayerScreenshot::LayerScreenshot(SurfaceFlinger* flinger, DisplayID display)
+ : LayerBase(flinger, display), mReply(0)
+{
+}
+
+LayerScreenshot::~LayerScreenshot()
+{
+}
+
+void LayerScreenshot::onDraw(const Region& clip) const
+{
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ copybit_image_t dst;
+ hw.getDisplaySurface(&dst);
+ if (dst.base != 0) {
+ uint8_t const* src = (uint8_t const*)(intptr_t(dst.base) + dst.offset);
+ const int fbWidth = dst.w;
+ const int fbHeight = dst.h;
+ const int fbFormat = dst.format;
+
+ int x = mTransformedBounds.left;
+ int y = mTransformedBounds.top;
+ int w = mTransformedBounds.width();
+ int h = mTransformedBounds.height();
+ Parcel* const reply = mReply;
+ if (reply) {
+ const size_t Bpp = bytesPerPixel(fbFormat);
+ const size_t size = w * h * Bpp;
+ int32_t cfg = SkBitmap::kNo_Config;
+ switch (fbFormat) {
+ case PIXEL_FORMAT_RGBA_4444: cfg = SkBitmap::kARGB_4444_Config; break;
+ case PIXEL_FORMAT_RGBA_8888: cfg = SkBitmap::kARGB_8888_Config; break;
+ case PIXEL_FORMAT_RGB_565: cfg = SkBitmap::kRGB_565_Config; break;
+ case PIXEL_FORMAT_A_8: cfg = SkBitmap::kA8_Config; break;
+ }
+ reply->writeInt32(0);
+ reply->writeInt32(cfg);
+ reply->writeInt32(w);
+ reply->writeInt32(h);
+ reply->writeInt32(w * Bpp);
+ void* data = reply->writeInplace(size);
+ if (data) {
+ uint8_t* d = (uint8_t*)data;
+ uint8_t const* s = src + (x + y*fbWidth) * Bpp;
+ if (w == fbWidth) {
+ memcpy(d, s, w*h*Bpp);
+ } else {
+ for (int y=0 ; y<h ; y++) {
+ memcpy(d, s, w*Bpp);
+ d += w*Bpp;
+ s += fbWidth*Bpp;
+ }
+ }
+ }
+ }
+ }
+ mCV.broadcast();
+}
+
+void LayerScreenshot::takeScreenshot(Mutex& lock, Parcel* reply)
+{
+ mReply = reply;
+ mCV.wait(lock);
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 0e998bf..efaf016 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -23,6 +23,7 @@
#include <fcntl.h>
#include <errno.h>
#include <math.h>
+#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
@@ -30,10 +31,10 @@
#include <cutils/log.h>
#include <cutils/properties.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
-#include <utils/MemoryDealer.h>
-#include <utils/MemoryBase.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/MemoryDealer.h>
+#include <binder/MemoryBase.h>
#include <utils/String8.h>
#include <utils/String16.h>
#include <utils/StopWatch.h>
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index 15913f2..126bce8 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -25,7 +25,7 @@
#include <utils/threads.h>
#include <utils/Atomic.h>
#include <utils/Errors.h>
-#include <utils/MemoryDealer.h>
+#include <binder/MemoryDealer.h>
#include <ui/PixelFormat.h>
#include <ui/ISurfaceComposer.h>
diff --git a/libs/surfaceflinger/VRamHeap.cpp b/libs/surfaceflinger/VRamHeap.cpp
index 5f633bd..68c0a5e 100644
--- a/libs/surfaceflinger/VRamHeap.cpp
+++ b/libs/surfaceflinger/VRamHeap.cpp
@@ -30,10 +30,10 @@
#include <cutils/log.h>
#include <cutils/properties.h>
-#include <utils/MemoryDealer.h>
-#include <utils/MemoryBase.h>
-#include <utils/MemoryHeapPmem.h>
-#include <utils/MemoryHeapBase.h>
+#include <binder/MemoryDealer.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapPmem.h>
+#include <binder/MemoryHeapBase.h>
#include <EGL/eglnatives.h>
diff --git a/libs/surfaceflinger/VRamHeap.h b/libs/surfaceflinger/VRamHeap.h
index 9140167..780a1bc 100644
--- a/libs/surfaceflinger/VRamHeap.h
+++ b/libs/surfaceflinger/VRamHeap.h
@@ -19,7 +19,7 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/MemoryDealer.h>
+#include <binder/MemoryDealer.h>
namespace android {
diff --git a/libs/surfaceflinger/tests/overlays/overlays.cpp b/libs/surfaceflinger/tests/overlays/overlays.cpp
index f3c046f..0b9322e 100644
--- a/libs/surfaceflinger/tests/overlays/overlays.cpp
+++ b/libs/surfaceflinger/tests/overlays/overlays.cpp
@@ -1,6 +1,6 @@
-#include <utils/IPCThreadState.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <ui/Surface.h>
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index b3b2104..c6fd070 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -31,6 +31,7 @@ LOCAL_SHARED_LIBRARIES := \
libcorecg \
libcutils \
libutils \
+ libbinder \
libpixelflinger \
libhardware \
libhardware_legacy
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 6613700..4228300 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -19,9 +19,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "Camera"
#include <utils/Log.h>
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <utils/threads.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <ui/Surface.h>
#include <ui/Camera.h>
#include <ui/ICameraService.h>
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 7c2fc8e..13c30a7 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -19,10 +19,11 @@
#include <hardware_legacy/power.h>
#include <cutils/properties.h>
-#include <utils/IServiceManager.h>
#include <utils/Log.h>
#include <utils/Timers.h>
-#include <utils.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <stdlib.h>
#include <stdio.h>
diff --git a/libs/ui/ICamera.cpp b/libs/ui/ICamera.cpp
index ab0fef1..805c2ca 100644
--- a/libs/ui/ICamera.cpp
+++ b/libs/ui/ICamera.cpp
@@ -20,7 +20,7 @@
#include <utils/Log.h>
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <ui/ICamera.h>
namespace android {
@@ -221,12 +221,6 @@ IMPLEMENT_META_INTERFACE(Camera, "android.hardware.ICamera");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnCamera::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/ui/ICameraClient.cpp b/libs/ui/ICameraClient.cpp
index c6cf75c..a88fd48 100644
--- a/libs/ui/ICameraClient.cpp
+++ b/libs/ui/ICameraClient.cpp
@@ -66,12 +66,6 @@ IMPLEMENT_META_INTERFACE(CameraClient, "android.hardware.ICameraClient");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnCameraClient::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/ui/ICameraService.cpp b/libs/ui/ICameraService.cpp
index e5687fe..84986c6 100644
--- a/libs/ui/ICameraService.cpp
+++ b/libs/ui/ICameraService.cpp
@@ -18,9 +18,9 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <ui/ICameraService.h>
@@ -49,12 +49,6 @@ IMPLEMENT_META_INTERFACE(CameraService, "android.hardware.ICameraService");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnCameraService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/ui/IOverlay.cpp b/libs/ui/IOverlay.cpp
index fed47c2..65e6b4f 100644
--- a/libs/ui/IOverlay.cpp
+++ b/libs/ui/IOverlay.cpp
@@ -18,8 +18,8 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/IInterface.h>
#include <ui/IOverlay.h>
@@ -49,12 +49,6 @@ IMPLEMENT_META_INTERFACE(Overlay, "android.ui.IOverlay");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnOverlay::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/ui/ISurface.cpp b/libs/ui/ISurface.cpp
index d5e9f81..1e60557 100644
--- a/libs/ui/ISurface.cpp
+++ b/libs/ui/ISurface.cpp
@@ -18,8 +18,8 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
#include <ui/ISurface.h>
#include <ui/Overlay.h>
@@ -112,12 +112,6 @@ IMPLEMENT_META_INTERFACE(Surface, "android.ui.ISurface");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnSurface::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/ui/ISurfaceComposer.cpp b/libs/ui/ISurfaceComposer.cpp
index 76597e1..5f558a1 100644
--- a/libs/ui/ISurfaceComposer.cpp
+++ b/libs/ui/ISurfaceComposer.cpp
@@ -20,10 +20,10 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <ui/ISurfaceComposer.h>
#include <ui/DisplayInfo.h>
@@ -156,62 +156,61 @@ IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnSurfaceComposer::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
- status_t err = BnInterface<ISurfaceComposer>::onTransact(code, data, reply, flags);
- if (err == NO_ERROR)
- return err;
-
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
-
switch(code) {
case CREATE_CONNECTION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> b = createConnection()->asBinder();
reply->writeStrongBinder(b);
} break;
case OPEN_GLOBAL_TRANSACTION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
openGlobalTransaction();
} break;
case CLOSE_GLOBAL_TRANSACTION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
closeGlobalTransaction();
} break;
case SET_ORIENTATION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
DisplayID dpy = data.readInt32();
int orientation = data.readInt32();
uint32_t flags = data.readInt32();
reply->writeInt32( setOrientation(dpy, orientation, flags) );
} break;
case FREEZE_DISPLAY: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
DisplayID dpy = data.readInt32();
uint32_t flags = data.readInt32();
reply->writeInt32( freezeDisplay(dpy, flags) );
} break;
case UNFREEZE_DISPLAY: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
DisplayID dpy = data.readInt32();
uint32_t flags = data.readInt32();
reply->writeInt32( unfreezeDisplay(dpy, flags) );
} break;
case BOOT_FINISHED: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
bootFinished();
} break;
case REVOKE_GPU: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
reply->writeInt32( revokeGPU() );
} break;
case SIGNAL: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
signal();
} break;
case GET_CBLK: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> b = getCblk()->asBinder();
reply->writeStrongBinder(b);
} break;
case REQUEST_GPU: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
// TODO: this should be protected by a permission
gpu_info_t info;
sp<IGPUCallback> callback
@@ -232,7 +231,7 @@ status_t BnSurfaceComposer::onTransact(
reply->writeInt32(res);
} break;
default:
- return UNKNOWN_TRANSACTION;
+ return BBinder::onTransact(code, data, reply, flags);
}
return NO_ERROR;
}
diff --git a/libs/ui/ISurfaceFlingerClient.cpp b/libs/ui/ISurfaceFlingerClient.cpp
index dab5f71..329bd6e 100644
--- a/libs/ui/ISurfaceFlingerClient.cpp
+++ b/libs/ui/ISurfaceFlingerClient.cpp
@@ -21,10 +21,10 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <ui/ISurface.h>
#include <ui/ISurfaceFlingerClient.h>
@@ -118,12 +118,6 @@ IMPLEMENT_META_INTERFACE(SurfaceFlingerClient, "android.ui.ISurfaceFlingerClient
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnSurfaceFlingerClient::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/libs/ui/LayerState.cpp b/libs/ui/LayerState.cpp
index 0b6374b..a53ffb7 100644
--- a/libs/ui/LayerState.cpp
+++ b/libs/ui/LayerState.cpp
@@ -15,7 +15,7 @@
*/
#include <utils/Errors.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <private/ui/LayerState.h>
namespace android {
diff --git a/libs/ui/Overlay.cpp b/libs/ui/Overlay.cpp
index 59c6514..a092f8d 100644
--- a/libs/ui/Overlay.cpp
+++ b/libs/ui/Overlay.cpp
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#include <utils/IMemory.h>
-#include <utils/Parcel.h>
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
#include <utils/Errors.h>
-#include <utils/MemoryHeapBase.h>
+#include <binder/MemoryHeapBase.h>
#include <ui/IOverlay.h>
#include <ui/Overlay.h>
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp
index 4ea9ae2..05cc529 100644
--- a/libs/ui/Surface.cpp
+++ b/libs/ui/Surface.cpp
@@ -26,8 +26,8 @@
#include <utils/Atomic.h>
#include <utils/Errors.h>
#include <utils/threads.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IMemory.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IMemory.h>
#include <utils/Log.h>
#include <ui/ISurface.h>
diff --git a/libs/ui/SurfaceComposerClient.cpp b/libs/ui/SurfaceComposerClient.cpp
index fe803ff..8acd2ee 100644
--- a/libs/ui/SurfaceComposerClient.cpp
+++ b/libs/ui/SurfaceComposerClient.cpp
@@ -29,9 +29,9 @@
#include <utils/Errors.h>
#include <utils/threads.h>
#include <utils/KeyedVector.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
-#include <utils/IMemory.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/IMemory.h>
#include <utils/Log.h>
#include <ui/ISurfaceComposer.h>
@@ -48,7 +48,7 @@
#include <pixelflinger/pixelflinger.h>
-#include <utils/BpBinder.h>
+#include <binder/BpBinder.h>
#define VERBOSE(...) ((void)0)
//#define VERBOSE LOGD
diff --git a/libs/ui/SurfaceFlingerSynchro.cpp b/libs/ui/SurfaceFlingerSynchro.cpp
index 5cd9755..2e8fa12 100644
--- a/libs/ui/SurfaceFlingerSynchro.cpp
+++ b/libs/ui/SurfaceFlingerSynchro.cpp
@@ -25,7 +25,7 @@
#include <sys/types.h>
#include <sys/stat.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IPCThreadState.h>
#include <utils/Log.h>
#include <private/ui/SurfaceFlingerSynchro.h>
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 9bdd64a..3f5cb85 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -32,51 +32,30 @@ commonSources:= \
StopWatch.cpp \
String8.cpp \
String16.cpp \
+ StringArray.cpp \
SystemClock.cpp \
TextOutput.cpp \
Threads.cpp \
- TimerProbe.cpp \
Timers.cpp \
VectorImpl.cpp \
ZipFileCRO.cpp \
ZipFileRO.cpp \
ZipUtils.cpp \
- misc.cpp \
- ported.cpp \
- LogSocket.cpp
+ misc.cpp
-#
-# The cpp files listed here do not belong in the device
-# build. Consult with the swetland before even thinking about
-# putting them in commonSources.
-#
-# They're used by the simulator runtime and by host-side tools like
-# aapt and the simulator front-end.
-#
-hostSources:= \
- InetAddress.cpp \
- Pipe.cpp \
- Socket.cpp \
- ZipEntry.cpp \
- ZipFile.cpp
# For the host
# =====================================================
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= $(commonSources) $(hostSources)
+LOCAL_SRC_FILES:= $(commonSources)
ifeq ($(HOST_OS),linux)
# Use the futex based mutex and condition variable
# implementation from android-arm because it's shared mem safe
LOCAL_SRC_FILES += \
- futex_synchro.c \
- executablepath_linux.cpp
-endif
-ifeq ($(HOST_OS),darwin)
- LOCAL_SRC_FILES += \
- executablepath_darwin.cpp
+ futex_synchro.c
endif
LOCAL_MODULE:= libutils
@@ -103,27 +82,10 @@ include $(CLEAR_VARS)
# we have the common sources, plus some device-specific stuff
LOCAL_SRC_FILES:= \
$(commonSources) \
- Binder.cpp \
- BpBinder.cpp \
- IInterface.cpp \
- IMemory.cpp \
- IPCThreadState.cpp \
- MemoryDealer.cpp \
- MemoryBase.cpp \
- MemoryHeapBase.cpp \
- MemoryHeapPmem.cpp \
- Parcel.cpp \
- ProcessState.cpp \
- IPermissionController.cpp \
- IServiceManager.cpp \
Unicode.cpp \
BackupData.cpp \
BackupHelpers.cpp
-ifeq ($(TARGET_SIMULATOR),true)
-LOCAL_SRC_FILES += $(hostSources)
-endif
-
ifeq ($(TARGET_OS),linux)
# Use the futex based mutex and condition variable
# implementation from android-arm because it's shared mem safe
@@ -150,9 +112,5 @@ endif # linux-x86
endif # sim
LOCAL_MODULE:= libutils
-
-#LOCAL_CFLAGS+=
-#LOCAL_LDFLAGS:=
-
include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/utils/CallStack.cpp b/libs/utils/CallStack.cpp
index 2fdaa71..55b6024 100644
--- a/libs/utils/CallStack.cpp
+++ b/libs/utils/CallStack.cpp
@@ -311,7 +311,8 @@ String8 CallStack::toStringSingleLevel(const char* prefix, int32_t level) const
} else {
void const* start = 0;
name = MapInfo::mapAddressToName(ip, "<unknown>", &start);
- snprintf(tmp, 256, "pc %08lx %s", uintptr_t(ip)-uintptr_t(start), name);
+ snprintf(tmp, 256, "pc %08lx %s",
+ long(uintptr_t(ip)-uintptr_t(start)), name);
res.append(tmp);
}
res.append("\n");
diff --git a/libs/utils/IDataConnection.cpp b/libs/utils/IDataConnection.cpp
deleted file mode 100644
index c6d49aa..0000000
--- a/libs/utils/IDataConnection.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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.
- */
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Parcel.h>
-
-#include <utils/IDataConnection.h>
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-enum
-{
- CONNECT_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
- DISCONNECT_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1
-};
-
-class BpDataConnection : public BpInterface<IDataConnection>
-{
-public:
- BpDataConnection::BpDataConnection(const sp<IBinder>& impl)
- : BpInterface<IDataConnection>(impl)
- {
- }
-
- virtual void connect()
- {
- Parcel data, reply;
- data.writeInterfaceToken(IDataConnection::descriptor());
- remote()->transact(CONNECT_TRANSACTION, data, &reply);
- }
-
- virtual void disconnect()
- {
- Parcel data, reply;
- remote()->transact(DISCONNECT_TRANSACTION, data, &reply);
- }
-};
-
-IMPLEMENT_META_INTERFACE(DataConnection, "android.utils.IDataConnection");
-
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
-status_t BnDataConnection::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code)
- {
- case CONNECT_TRANSACTION:
- {
- CHECK_INTERFACE(IDataConnection, data, reply);
- connect();
- return NO_ERROR;
- }
-
- case DISCONNECT_TRANSACTION:
- {
- CHECK_INTERFACE(IDataConnection, data, reply);
- disconnect();
- return NO_ERROR;
- }
-
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/libs/utils/InetAddress.cpp b/libs/utils/InetAddress.cpp
deleted file mode 100644
index 39a0a68..0000000
--- a/libs/utils/InetAddress.cpp
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Internet address class.
-//
-#ifdef HAVE_WINSOCK
-# include <winsock2.h>
-#else
-# include <sys/types.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
-//# include <arpa/inet.h>
-# include <netdb.h>
-#endif
-
-#include <utils/inet_address.h>
-#include <utils/threads.h>
-#include <utils/Log.h>
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-using namespace android;
-
-
-/*
- * ===========================================================================
- * InetAddress
- * ===========================================================================
- */
-
-// lock for the next couple of functions; could tuck into InetAddress
-static Mutex* gGHBNLock;
-
-/*
- * Lock/unlock access to the hostent struct returned by gethostbyname().
- */
-static inline void lock_gethostbyname(void)
-{
- if (gGHBNLock == NULL)
- gGHBNLock = new Mutex;
- gGHBNLock->lock();
-}
-static inline void unlock_gethostbyname(void)
-{
- assert(gGHBNLock != NULL);
- gGHBNLock->unlock();
-}
-
-
-/*
- * Constructor -- just init members. This is private so that callers
- * are required to use getByName().
- */
-InetAddress::InetAddress(void)
- : mAddress(NULL), mLength(-1), mName(NULL)
-{
-}
-
-/*
- * Destructor -- free address storage.
- */
-InetAddress::~InetAddress(void)
-{
- delete[] (char*) mAddress;
- delete[] mName;
-}
-
-/*
- * Copy constructor.
- */
-InetAddress::InetAddress(const InetAddress& orig)
-{
- *this = orig; // use assignment code
-}
-
-/*
- * Assignment operator.
- */
-InetAddress& InetAddress::operator=(const InetAddress& addr)
-{
- // handle self-assignment
- if (this == &addr)
- return *this;
- // copy mLength and mAddress
- mLength = addr.mLength;
- if (mLength > 0) {
- mAddress = new char[mLength];
- memcpy(mAddress, addr.mAddress, mLength);
- LOG(LOG_DEBUG, "socket",
- "HEY: copied %d bytes in assignment operator\n", mLength);
- } else {
- mAddress = NULL;
- }
- // copy mName
- mName = new char[strlen(addr.mName)+1];
- strcpy(mName, addr.mName);
-
- return *this;
-}
-
-/*
- * Create a new object from a name or a dotted-number IP notation.
- *
- * Returns NULL on failure.
- */
-InetAddress*
-InetAddress::getByName(const char* host)
-{
- InetAddress* newAddr = NULL;
- struct sockaddr_in addr;
- struct hostent* he;
- DurationTimer hostTimer, lockTimer;
-
- // gethostbyname() isn't reentrant, so we need to lock things until
- // we can copy the data out.
- lockTimer.start();
- lock_gethostbyname();
- hostTimer.start();
-
- he = gethostbyname(host);
- if (he == NULL) {
- LOG(LOG_WARN, "socket", "WARNING: cannot resolve host %s\n", host);
- unlock_gethostbyname();
- return NULL;
- }
-
- memcpy(&addr.sin_addr, he->h_addr, he->h_length);
- addr.sin_family = he->h_addrtype;
- addr.sin_port = 0;
-
- // got it, unlock us
- hostTimer.stop();
- he = NULL;
- unlock_gethostbyname();
-
- lockTimer.stop();
- if ((long) lockTimer.durationUsecs() > 100000) {
- long lockTime = (long) lockTimer.durationUsecs();
- long hostTime = (long) hostTimer.durationUsecs();
- LOG(LOG_DEBUG, "socket",
- "Lookup of %s took %.3fs (gethostbyname=%.3fs lock=%.3fs)\n",
- host, lockTime / 1000000.0, hostTime / 1000000.0,
- (lockTime - hostTime) / 1000000.0);
- }
-
- // Alloc storage and copy it over.
- newAddr = new InetAddress();
- if (newAddr == NULL)
- return NULL;
-
- newAddr->mLength = sizeof(struct sockaddr_in);
- newAddr->mAddress = new char[sizeof(struct sockaddr_in)];
- if (newAddr->mAddress == NULL) {
- delete newAddr;
- return NULL;
- }
- memcpy(newAddr->mAddress, &addr, newAddr->mLength);
-
- // Keep this for debug messages.
- newAddr->mName = new char[strlen(host)+1];
- if (newAddr->mName == NULL) {
- delete newAddr;
- return NULL;
- }
- strcpy(newAddr->mName, host);
-
- return newAddr;
-}
-
-
-/*
- * ===========================================================================
- * InetSocketAddress
- * ===========================================================================
- */
-
-/*
- * Create an address with the host wildcard (INADDR_ANY).
- */
-bool InetSocketAddress::create(int port)
-{
- assert(mAddress == NULL);
-
- mAddress = InetAddress::getByName("0.0.0.0");
- if (mAddress == NULL)
- return false;
- mPort = port;
- return true;
-}
-
-/*
- * Create address with host and port specified.
- */
-bool InetSocketAddress::create(const InetAddress* addr, int port)
-{
- assert(mAddress == NULL);
-
- mAddress = new InetAddress(*addr); // make a copy
- if (mAddress == NULL)
- return false;
- mPort = port;
- return true;
-}
-
-/*
- * Create address with host and port specified.
- */
-bool InetSocketAddress::create(const char* host, int port)
-{
- assert(mAddress == NULL);
-
- mAddress = InetAddress::getByName(host);
- if (mAddress == NULL)
- return false;
- mPort = port;
- return true;
-}
-
diff --git a/libs/utils/LogSocket.cpp b/libs/utils/LogSocket.cpp
deleted file mode 100644
index 55c1b99..0000000
--- a/libs/utils/LogSocket.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#ifndef HAVE_WINSOCK
-//#define SOCKETLOG
-#endif
-
-#ifdef SOCKETLOG
-
-#define LOG_TAG "SOCKETLOG"
-
-#include <string.h>
-#include <cutils/log.h>
-#include "utils/LogSocket.h"
-#include "utils/logger.h"
-#include "cutils/hashmap.h"
-
-// defined in //device/data/etc/event-log-tags
-#define SOCKET_CLOSE_LOG 51000
-
-static Hashmap* statsMap = NULL;
-
-#define LOG_LIST_NUMBER 5
-
-typedef struct SocketStats {
- int fd;
- unsigned int send;
- unsigned int recv;
- unsigned int ip;
- unsigned short port;
- short reason;
-}SocketStats;
-
-SocketStats *get_socket_stats(int fd) {
- if (statsMap == NULL) {
- statsMap = hashmapCreate(8, &hashmapIntHash, &hashmapIntEquals);
- }
-
- SocketStats *s = (SocketStats*) hashmapGet(statsMap, &fd);
- if (s == NULL) {
- // LOGD("create SocketStats for fd %d", fd);
- s = (SocketStats*) malloc(sizeof(SocketStats));
- memset(s, 0, sizeof(SocketStats));
- s->fd = fd;
- hashmapPut(statsMap, &s->fd, s);
- }
- return s;
-}
-
-void log_socket_connect(int fd, unsigned int ip, unsigned short port) {
- // LOGD("log_socket_connect for fd %d ip %d port%d", fd, ip, port);
- SocketStats *s = get_socket_stats(fd);
- s->ip = ip;
- s->port = port;
-}
-
-void add_send_stats(int fd, int send) {
- if (send <=0) {
- LOGE("add_send_stats send %d", send);
- return;
- }
- SocketStats *s = get_socket_stats(fd);
- s->send += send;
- // LOGD("add_send_stats for fd %d ip %d port%d", fd, s->ip, s->port);
-}
-
-void add_recv_stats(int fd, int recv) {
- if (recv <=0) {
- LOGE("add_recv_stats recv %d", recv);
- return;
- }
- SocketStats *s = get_socket_stats(fd);
- s->recv += recv;
- // LOGD("add_recv_stats for fd %d ip %d port%d", fd, s->ip, s->port);
-}
-
-char* put_int(char* buf, int value) {
- *buf = EVENT_TYPE_INT;
- buf++;
- memcpy(buf, &value, sizeof(int));
- return buf + sizeof(int);
-}
-
-void log_socket_close(int fd, short reason) {
- if (statsMap) {
- SocketStats *s = (SocketStats*) hashmapGet(statsMap, &fd);
- if (s != NULL) {
- if (s->send != 0 || s->recv != 0) {
- s->reason = reason;
- // 5 int + list type need 2 bytes
- char buf[LOG_LIST_NUMBER * 5 + 2];
- buf[0] = EVENT_TYPE_LIST;
- buf[1] = LOG_LIST_NUMBER;
- char* writePos = buf + 2;
- writePos = put_int(writePos, s->send);
- writePos = put_int(writePos, s->recv);
- writePos = put_int(writePos, s->ip);
- writePos = put_int(writePos, s->port);
- writePos = put_int(writePos, s->reason);
-
- android_bWriteLog(SOCKET_CLOSE_LOG, buf, sizeof(buf));
- // LOGD("send %d recv %d reason %d", s->send, s->recv, s->reason);
- }
- hashmapRemove(statsMap, &s->fd);
- free(s);
- }
- }
-}
-
-#else
-void add_send_stats(int fd, int send) {}
-void add_recv_stats(int fd, int recv) {}
-void log_socket_close(int fd, short reason) {}
-void log_socket_connect(int fd, unsigned int ip, unsigned short port) {}
-#endif
diff --git a/libs/utils/Pipe.cpp b/libs/utils/Pipe.cpp
deleted file mode 100644
index 613906b..0000000
--- a/libs/utils/Pipe.cpp
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Unidirectional pipe.
-//
-
-#include <utils/Pipe.h>
-#include <utils/Log.h>
-
-#if defined(HAVE_WIN32_IPC)
-# include <windows.h>
-#else
-# include <fcntl.h>
-# include <unistd.h>
-# include <errno.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
-
-using namespace android;
-
-const unsigned long kInvalidHandle = (unsigned long) -1;
-
-
-/*
- * Constructor. Do little.
- */
-Pipe::Pipe(void)
- : mReadNonBlocking(false), mReadHandle(kInvalidHandle),
- mWriteHandle(kInvalidHandle)
-{
-}
-
-/*
- * Destructor. Use the system-appropriate close call.
- */
-Pipe::~Pipe(void)
-{
-#if defined(HAVE_WIN32_IPC)
- if (mReadHandle != kInvalidHandle) {
- if (!CloseHandle((HANDLE)mReadHandle))
- LOG(LOG_WARN, "pipe", "failed closing read handle (%ld)\n",
- mReadHandle);
- }
- if (mWriteHandle != kInvalidHandle) {
- FlushFileBuffers((HANDLE)mWriteHandle);
- if (!CloseHandle((HANDLE)mWriteHandle))
- LOG(LOG_WARN, "pipe", "failed closing write handle (%ld)\n",
- mWriteHandle);
- }
-#else
- if (mReadHandle != kInvalidHandle) {
- if (close((int) mReadHandle) != 0)
- LOG(LOG_WARN, "pipe", "failed closing read fd (%d)\n",
- (int) mReadHandle);
- }
- if (mWriteHandle != kInvalidHandle) {
- if (close((int) mWriteHandle) != 0)
- LOG(LOG_WARN, "pipe", "failed closing write fd (%d)\n",
- (int) mWriteHandle);
- }
-#endif
-}
-
-/*
- * Create the pipe.
- *
- * Use the POSIX stuff for everything but Windows.
- */
-bool Pipe::create(void)
-{
- assert(mReadHandle == kInvalidHandle);
- assert(mWriteHandle == kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
- /* we use this across processes, so they need to be inheritable */
- HANDLE handles[2];
- SECURITY_ATTRIBUTES saAttr;
-
- saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
- saAttr.bInheritHandle = TRUE;
- saAttr.lpSecurityDescriptor = NULL;
-
- if (!CreatePipe(&handles[0], &handles[1], &saAttr, 0)) {
- LOG(LOG_ERROR, "pipe", "unable to create pipe\n");
- return false;
- }
- mReadHandle = (unsigned long) handles[0];
- mWriteHandle = (unsigned long) handles[1];
- return true;
-#else
- int fds[2];
-
- if (pipe(fds) != 0) {
- LOG(LOG_ERROR, "pipe", "unable to create pipe\n");
- return false;
- }
- mReadHandle = fds[0];
- mWriteHandle = fds[1];
- return true;
-#endif
-}
-
-/*
- * Create a "half pipe". Please, no Segway riding.
- */
-bool Pipe::createReader(unsigned long handle)
-{
- mReadHandle = handle;
- assert(mWriteHandle == kInvalidHandle);
- return true;
-}
-
-/*
- * Create a "half pipe" for writing.
- */
-bool Pipe::createWriter(unsigned long handle)
-{
- mWriteHandle = handle;
- assert(mReadHandle == kInvalidHandle);
- return true;
-}
-
-/*
- * Return "true" if create() has been called successfully.
- */
-bool Pipe::isCreated(void)
-{
- // one or the other should be open
- return (mReadHandle != kInvalidHandle || mWriteHandle != kInvalidHandle);
-}
-
-
-/*
- * Read data from the pipe.
- *
- * For Linux and Darwin, just call read(). For Windows, implement
- * non-blocking reads by calling PeekNamedPipe first.
- */
-int Pipe::read(void* buf, int count)
-{
- assert(mReadHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
- DWORD totalBytesAvail = count;
- DWORD bytesRead;
-
- if (mReadNonBlocking) {
- // use PeekNamedPipe to adjust read count expectations
- if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL,
- &totalBytesAvail, NULL))
- {
- LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n");
- return -1;
- }
-
- if (totalBytesAvail == 0)
- return 0;
- }
-
- if (!ReadFile((HANDLE) mReadHandle, buf, totalBytesAvail, &bytesRead,
- NULL))
- {
- DWORD err = GetLastError();
- if (err == ERROR_HANDLE_EOF || err == ERROR_BROKEN_PIPE)
- return 0;
- LOG(LOG_ERROR, "pipe", "ReadFile failed (err=%ld)\n", err);
- return -1;
- }
-
- return (int) bytesRead;
-#else
- int cc;
- cc = ::read(mReadHandle, buf, count);
- if (cc < 0 && errno == EAGAIN)
- return 0;
- return cc;
-#endif
-}
-
-/*
- * Write data to the pipe.
- *
- * POSIX systems are trivial, Windows uses a different call and doesn't
- * handle non-blocking writes.
- *
- * If we add non-blocking support here, we probably want to make it an
- * all-or-nothing write.
- *
- * DO NOT use LOG() here, we could be writing a log message.
- */
-int Pipe::write(const void* buf, int count)
-{
- assert(mWriteHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
- DWORD bytesWritten;
-
- if (mWriteNonBlocking) {
- // BUG: can't use PeekNamedPipe() to get the amount of space
- // left. Looks like we need to use "overlapped I/O" functions.
- // I just don't care that much.
- }
-
- if (!WriteFile((HANDLE) mWriteHandle, buf, count, &bytesWritten, NULL)) {
- // can't LOG, use stderr
- fprintf(stderr, "WriteFile failed (err=%ld)\n", GetLastError());
- return -1;
- }
-
- return (int) bytesWritten;
-#else
- int cc;
- cc = ::write(mWriteHandle, buf, count);
- if (cc < 0 && errno == EAGAIN)
- return 0;
- return cc;
-#endif
-}
-
-/*
- * Figure out if there is data available on the read fd.
- *
- * We return "true" on error because we want the caller to try to read
- * from the pipe. They'll notice the read failure and do something
- * appropriate.
- */
-bool Pipe::readReady(void)
-{
- assert(mReadHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
- DWORD totalBytesAvail;
-
- if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL,
- &totalBytesAvail, NULL))
- {
- LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n");
- return true;
- }
-
- return (totalBytesAvail != 0);
-#else
- errno = 0;
- fd_set readfds;
- struct timeval tv = { 0, 0 };
- int cc;
-
- FD_ZERO(&readfds);
- FD_SET(mReadHandle, &readfds);
-
- cc = select(mReadHandle+1, &readfds, NULL, NULL, &tv);
- if (cc < 0) {
- LOG(LOG_ERROR, "pipe", "select() failed\n");
- return true;
- } else if (cc == 0) {
- /* timed out, nothing available */
- return false;
- } else if (cc == 1) {
- /* our fd is ready */
- return true;
- } else {
- LOG(LOG_ERROR, "pipe", "HUH? select() returned > 1\n");
- return true;
- }
-#endif
-}
-
-/*
- * Enable or disable non-blocking mode for the read descriptor.
- *
- * NOTE: the calls succeed under Mac OS X, but the pipe doesn't appear to
- * actually be in non-blocking mode. If this matters -- i.e. you're not
- * using a select() call -- put a call to readReady() in front of the
- * ::read() call, with a PIPE_NONBLOCK_BROKEN #ifdef in the Makefile for
- * Darwin.
- */
-bool Pipe::setReadNonBlocking(bool val)
-{
- assert(mReadHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
- // nothing to do
-#else
- int flags;
-
- if (fcntl(mReadHandle, F_GETFL, &flags) == -1) {
- LOG(LOG_ERROR, "pipe", "couldn't get flags for pipe read fd\n");
- return false;
- }
- if (val)
- flags |= O_NONBLOCK;
- else
- flags &= ~(O_NONBLOCK);
- if (fcntl(mReadHandle, F_SETFL, &flags) == -1) {
- LOG(LOG_ERROR, "pipe", "couldn't set flags for pipe read fd\n");
- return false;
- }
-#endif
-
- mReadNonBlocking = val;
- return true;
-}
-
-/*
- * Enable or disable non-blocking mode for the write descriptor.
- *
- * As with setReadNonBlocking(), this does not work on the Mac.
- */
-bool Pipe::setWriteNonBlocking(bool val)
-{
- assert(mWriteHandle != kInvalidHandle);
-
-#if defined(HAVE_WIN32_IPC)
- // nothing to do
-#else
- int flags;
-
- if (fcntl(mWriteHandle, F_GETFL, &flags) == -1) {
- LOG(LOG_WARN, "pipe",
- "Warning: couldn't get flags for pipe write fd (errno=%d)\n",
- errno);
- return false;
- }
- if (val)
- flags |= O_NONBLOCK;
- else
- flags &= ~(O_NONBLOCK);
- if (fcntl(mWriteHandle, F_SETFL, &flags) == -1) {
- LOG(LOG_WARN, "pipe",
- "Warning: couldn't set flags for pipe write fd (errno=%d)\n",
- errno);
- return false;
- }
-#endif
-
- mWriteNonBlocking = val;
- return true;
-}
-
-/*
- * Specify whether a file descriptor can be inherited by a child process.
- * Under Linux this means setting the close-on-exec flag, under Windows
- * this is SetHandleInformation(HANDLE_FLAG_INHERIT).
- */
-bool Pipe::disallowReadInherit(void)
-{
- if (mReadHandle == kInvalidHandle)
- return false;
-
-#if defined(HAVE_WIN32_IPC)
- if (SetHandleInformation((HANDLE) mReadHandle, HANDLE_FLAG_INHERIT, 0) == 0)
- return false;
-#else
- if (fcntl((int) mReadHandle, F_SETFD, FD_CLOEXEC) != 0)
- return false;
-#endif
- return true;
-}
-bool Pipe::disallowWriteInherit(void)
-{
- if (mWriteHandle == kInvalidHandle)
- return false;
-
-#if defined(HAVE_WIN32_IPC)
- if (SetHandleInformation((HANDLE) mWriteHandle, HANDLE_FLAG_INHERIT, 0) == 0)
- return false;
-#else
- if (fcntl((int) mWriteHandle, F_SETFD, FD_CLOEXEC) != 0)
- return false;
-#endif
- return true;
-}
-
-/*
- * Close read descriptor.
- */
-bool Pipe::closeRead(void)
-{
- if (mReadHandle == kInvalidHandle)
- return false;
-
-#if defined(HAVE_WIN32_IPC)
- if (mReadHandle != kInvalidHandle) {
- if (!CloseHandle((HANDLE)mReadHandle)) {
- LOG(LOG_WARN, "pipe", "failed closing read handle\n");
- return false;
- }
- }
-#else
- if (mReadHandle != kInvalidHandle) {
- if (close((int) mReadHandle) != 0) {
- LOG(LOG_WARN, "pipe", "failed closing read fd\n");
- return false;
- }
- }
-#endif
- mReadHandle = kInvalidHandle;
- return true;
-}
-
-/*
- * Close write descriptor.
- */
-bool Pipe::closeWrite(void)
-{
- if (mWriteHandle == kInvalidHandle)
- return false;
-
-#if defined(HAVE_WIN32_IPC)
- if (mWriteHandle != kInvalidHandle) {
- if (!CloseHandle((HANDLE)mWriteHandle)) {
- LOG(LOG_WARN, "pipe", "failed closing write handle\n");
- return false;
- }
- }
-#else
- if (mWriteHandle != kInvalidHandle) {
- if (close((int) mWriteHandle) != 0) {
- LOG(LOG_WARN, "pipe", "failed closing write fd\n");
- return false;
- }
- }
-#endif
- mWriteHandle = kInvalidHandle;
- return true;
-}
-
-/*
- * Get the read handle.
- */
-unsigned long Pipe::getReadHandle(void)
-{
- assert(mReadHandle != kInvalidHandle);
-
- return mReadHandle;
-}
-
-/*
- * Get the write handle.
- */
-unsigned long Pipe::getWriteHandle(void)
-{
- assert(mWriteHandle != kInvalidHandle);
-
- return mWriteHandle;
-}
-
diff --git a/libs/utils/Socket.cpp b/libs/utils/Socket.cpp
deleted file mode 100644
index 51509a3..0000000
--- a/libs/utils/Socket.cpp
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Internet address class.
-//
-
-#ifdef HAVE_WINSOCK
-// This needs to come first, or Cygwin gets concerned about a potential
-// clash between WinSock and <sys/types.h>.
-# include <winsock2.h>
-#endif
-
-#include <utils/Socket.h>
-#include <utils/inet_address.h>
-#include <utils/Log.h>
-#include <utils/Timers.h>
-
-#ifndef HAVE_WINSOCK
-# include <sys/types.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <arpa/inet.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-
-using namespace android;
-
-
-/*
- * ===========================================================================
- * Socket
- * ===========================================================================
- */
-
-#ifndef INVALID_SOCKET
-# define INVALID_SOCKET (-1)
-#endif
-#define UNDEF_SOCKET ((unsigned long) INVALID_SOCKET)
-
-/*static*/ bool Socket::mBootInitialized = false;
-
-/*
- * Extract system-dependent error code.
- */
-static inline int getSocketError(void) {
-#ifdef HAVE_WINSOCK
- return WSAGetLastError();
-#else
- return errno;
-#endif
-}
-
-/*
- * One-time initialization for socket code.
- */
-/*static*/ bool Socket::bootInit(void)
-{
-#ifdef HAVE_WINSOCK
- WSADATA wsaData;
- int err;
-
- err = WSAStartup(MAKEWORD(2, 0), &wsaData);
- if (err != 0) {
- LOG(LOG_ERROR, "socket", "Unable to start WinSock\n");
- return false;
- }
-
- LOG(LOG_INFO, "socket", "Using WinSock v%d.%d\n",
- LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
-#endif
-
- mBootInitialized = true;
- return true;
-}
-
-/*
- * One-time shutdown for socket code.
- */
-/*static*/ void Socket::finalShutdown(void)
-{
-#ifdef HAVE_WINSOCK
- WSACleanup();
-#endif
- mBootInitialized = false;
-}
-
-
-/*
- * Simple constructor. Allow the application to create us and then make
- * bind/connect calls.
- */
-Socket::Socket(void)
- : mSock(UNDEF_SOCKET)
-{
- if (!mBootInitialized)
- LOG(LOG_WARN, "socket", "WARNING: sockets not initialized\n");
-}
-
-/*
- * Destructor. Closes the socket and resets our storage.
- */
-Socket::~Socket(void)
-{
- close();
-}
-
-
-/*
- * Create a socket and connect to the specified host and port.
- */
-int Socket::connect(const char* host, int port)
-{
- if (mSock != UNDEF_SOCKET) {
- LOG(LOG_WARN, "socket", "Socket already connected\n");
- return -1;
- }
-
- InetSocketAddress sockAddr;
- if (!sockAddr.create(host, port))
- return -1;
-
- //return doConnect(sockAddr);
- int foo;
- foo = doConnect(sockAddr);
- return foo;
-}
-
-/*
- * Create a socket and connect to the specified host and port.
- */
-int Socket::connect(const InetAddress* addr, int port)
-{
- if (mSock != UNDEF_SOCKET) {
- LOG(LOG_WARN, "socket", "Socket already connected\n");
- return -1;
- }
-
- InetSocketAddress sockAddr;
- if (!sockAddr.create(addr, port))
- return -1;
-
- return doConnect(sockAddr);
-}
-
-/*
- * Finish creating a socket by connecting to the remote host.
- *
- * Returns 0 on success.
- */
-int Socket::doConnect(const InetSocketAddress& sockAddr)
-{
-#ifdef HAVE_WINSOCK
- SOCKET sock;
-#else
- int sock;
-#endif
- const InetAddress* addr = sockAddr.getAddress();
- int port = sockAddr.getPort();
- struct sockaddr_in inaddr;
- DurationTimer connectTimer;
-
- assert(sizeof(struct sockaddr_in) == addr->getAddressLength());
- memcpy(&inaddr, addr->getAddress(), addr->getAddressLength());
- inaddr.sin_port = htons(port);
-
- //fprintf(stderr, "--- connecting to %s:%d\n",
- // sockAddr.getHostName(), port);
-
- sock = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (sock == INVALID_SOCKET) {
- int err = getSocketError();
- LOG(LOG_ERROR, "socket", "Unable to create socket (err=%d)\n", err);
- return (err != 0) ? err : -1;
- }
-
- connectTimer.start();
-
- if (::connect(sock, (struct sockaddr*) &inaddr, sizeof(inaddr)) != 0) {
- int err = getSocketError();
- LOG(LOG_WARN, "socket", "Connect to %s:%d failed: %d\n",
- sockAddr.getHostName(), port, err);
- return (err != 0) ? err : -1;
- }
-
- connectTimer.stop();
- if ((long) connectTimer.durationUsecs() > 100000) {
- LOG(LOG_INFO, "socket",
- "Connect to %s:%d took %.3fs\n", sockAddr.getHostName(),
- port, ((long) connectTimer.durationUsecs()) / 1000000.0);
- }
-
- mSock = (unsigned long) sock;
- LOG(LOG_VERBOSE, "socket",
- "--- connected to %s:%d\n", sockAddr.getHostName(), port);
- return 0;
-}
-
-
-/*
- * Close the socket if it needs closing.
- */
-bool Socket::close(void)
-{
- if (mSock != UNDEF_SOCKET) {
- //fprintf(stderr, "--- closing socket %lu\n", mSock);
-#ifdef HAVE_WINSOCK
- if (::closesocket((SOCKET) mSock) != 0)
- return false;
-#else
- if (::close((int) mSock) != 0)
- return false;
-#endif
- }
-
- mSock = UNDEF_SOCKET;
-
- return true;
-}
-
-/*
- * Read data from socket.
- *
- * Standard semantics: read up to "len" bytes into "buf". Returns the
- * number of bytes read, or less than zero on error.
- */
-int Socket::read(void* buf, ssize_t len) const
-{
- if (mSock == UNDEF_SOCKET) {
- LOG(LOG_ERROR, "socket", "ERROR: read on invalid socket\n");
- return -500;
- }
-
-#ifdef HAVE_WINSOCK
- SOCKET sock = (SOCKET) mSock;
-#else
- int sock = (int) mSock;
-#endif
- int cc;
-
- cc = recv(sock, (char*)buf, len, 0);
- if (cc < 0) {
- int err = getSocketError();
- return (err > 0) ? -err : -1;
- }
-
- return cc;
-}
-
-/*
- * Write data to a socket.
- *
- * Standard semantics: write up to "len" bytes into "buf". Returns the
- * number of bytes written, or less than zero on error.
- */
-int Socket::write(const void* buf, ssize_t len) const
-{
- if (mSock == UNDEF_SOCKET) {
- LOG(LOG_ERROR, "socket", "ERROR: write on invalid socket\n");
- return -500;
- }
-
-#ifdef HAVE_WINSOCK
- SOCKET sock = (SOCKET) mSock;
-#else
- int sock = (int) mSock;
-#endif
- int cc;
-
- cc = send(sock, (const char*)buf, len, 0);
- if (cc < 0) {
- int err = getSocketError();
- return (err > 0) ? -err : -1;
- }
-
- return cc;
-}
-
-
-/*
- * ===========================================================================
- * Socket tests
- * ===========================================================================
- */
-
-/*
- * Read all data from the socket. The data is read into a buffer that
- * expands as needed.
- *
- * On exit, the buffer is returned, and the length of the data is stored
- * in "*sz". A null byte is added to the end, but is not included in
- * the length.
- */
-static char* socketReadAll(const Socket& s, int *sz)
-{
- int max, r;
- char *data, *ptr, *tmp;
-
- data = (char*) malloc(max = 32768);
- if (data == NULL)
- return NULL;
-
- ptr = data;
-
- for (;;) {
- if ((ptr - data) == max) {
- tmp = (char*) realloc(data, max *= 2);
- if(tmp == 0) {
- free(data);
- return 0;
- }
- }
- r = s.read(ptr, max - (ptr - data));
- if (r == 0)
- break;
- if (r < 0) {
- LOG(LOG_WARN, "socket", "WARNING: socket read failed (res=%d)\n",r);
- break;
- }
- ptr += r;
- }
-
- if ((ptr - data) == max) {
- tmp = (char*) realloc(data, max + 1);
- if (tmp == NULL) {
- free(data);
- return NULL;
- }
- }
- *ptr = '\0';
- *sz = (ptr - data);
- return data;
-}
-
-/*
- * Exercise the Socket class.
- */
-void android::TestSockets(void)
-{
- printf("----- SOCKET TEST ------\n");
- Socket::bootInit();
-
- char* buf = NULL;
- int len, cc;
- const char* kTestStr =
- "GET / HTTP/1.0\n"
- "Connection: close\n"
- "\n";
-
- Socket sock;
- if (sock.connect("www.google.com", 80) != 0) {
- fprintf(stderr, "socket connected failed\n");
- goto bail;
- }
-
- cc = sock.write(kTestStr, strlen(kTestStr));
- if (cc != (int) strlen(kTestStr)) {
- fprintf(stderr, "write failed, res=%d\n", cc);
- goto bail;
- }
- buf = socketReadAll(sock, &len);
-
- printf("GOT '%s'\n", buf);
-
-bail:
- sock.close();
- free(buf);
-}
-
diff --git a/libs/utils/Static.cpp b/libs/utils/Static.cpp
index 93f7e4f..4dfa578 100644
--- a/libs/utils/Static.cpp
+++ b/libs/utils/Static.cpp
@@ -20,7 +20,6 @@
#include <private/utils/Static.h>
#include <utils/BufferedTextOutput.h>
-#include <utils/IPCThreadState.h>
#include <utils/Log.h>
namespace android {
@@ -87,34 +86,4 @@ TextOutput& alog(gLogTextOutput);
TextOutput& aout(gStdoutTextOutput);
TextOutput& aerr(gStderrTextOutput);
-#ifndef LIBUTILS_NATIVE
-
-// ------------ ProcessState.cpp
-
-Mutex gProcessMutex;
-sp<ProcessState> gProcess;
-
-class LibUtilsIPCtStatics
-{
-public:
- LibUtilsIPCtStatics()
- {
- }
-
- ~LibUtilsIPCtStatics()
- {
- IPCThreadState::shutdown();
- }
-};
-
-static LibUtilsIPCtStatics gIPCStatics;
-
-// ------------ ServiceManager.cpp
-
-Mutex gDefaultServiceManagerLock;
-sp<IServiceManager> gDefaultServiceManager;
-sp<IPermissionController> gPermissionController;
-
-#endif
-
} // namespace android
diff --git a/libs/utils/StringArray.cpp b/libs/utils/StringArray.cpp
new file mode 100644
index 0000000..aa42d68
--- /dev/null
+++ b/libs/utils/StringArray.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+//
+// Sortable array of strings. STL-ish, but STL-free.
+//
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <utils/StringArray.h>
+
+namespace android {
+
+//
+// An expanding array of strings. Add, get, sort, delete.
+//
+StringArray::StringArray()
+ : mMax(0), mCurrent(0), mArray(NULL)
+{
+}
+
+StringArray:: ~StringArray() {
+ for (int i = 0; i < mCurrent; i++)
+ delete[] mArray[i];
+ delete[] mArray;
+}
+
+//
+// Add a string. A copy of the string is made.
+//
+bool StringArray::push_back(const char* str) {
+ if (mCurrent >= mMax) {
+ char** tmp;
+
+ if (mMax == 0)
+ mMax = 16; // initial storage
+ else
+ mMax *= 2;
+
+ tmp = new char*[mMax];
+ if (tmp == NULL)
+ return false;
+
+ memcpy(tmp, mArray, mCurrent * sizeof(char*));
+ delete[] mArray;
+ mArray = tmp;
+ }
+
+ int len = strlen(str);
+ mArray[mCurrent] = new char[len+1];
+ memcpy(mArray[mCurrent], str, len+1);
+ mCurrent++;
+
+ return true;
+}
+
+//
+// Delete an entry.
+//
+void StringArray::erase(int idx) {
+ if (idx < 0 || idx >= mCurrent)
+ return;
+ delete[] mArray[idx];
+ if (idx < mCurrent-1) {
+ memmove(&mArray[idx], &mArray[idx+1],
+ (mCurrent-1 - idx) * sizeof(char*));
+ }
+ mCurrent--;
+}
+
+//
+// Sort the array.
+//
+void StringArray::sort(int (*compare)(const void*, const void*)) {
+ qsort(mArray, mCurrent, sizeof(char*), compare);
+}
+
+//
+// Pass this to the sort routine to do an ascending alphabetical sort.
+//
+int StringArray::cmpAscendingAlpha(const void* pstr1, const void* pstr2) {
+ return strcmp(*(const char**)pstr1, *(const char**)pstr2);
+}
+
+//
+// Set entry N to specified string.
+// [should use operator[] here]
+//
+void StringArray::setEntry(int idx, const char* str) {
+ if (idx < 0 || idx >= mCurrent)
+ return;
+ delete[] mArray[idx];
+ int len = strlen(str);
+ mArray[idx] = new char[len+1];
+ memcpy(mArray[idx], str, len+1);
+}
+
+
+}; // namespace android
diff --git a/libs/utils/TextOutput.cpp b/libs/utils/TextOutput.cpp
index cebee99..e04823d 100644
--- a/libs/utils/TextOutput.cpp
+++ b/libs/utils/TextOutput.cpp
@@ -22,9 +22,17 @@
#include <stdlib.h>
#include <string.h>
+namespace android {
+
// ---------------------------------------------------------------------------
-namespace android {
+TextOutput::TextOutput() {
+}
+
+TextOutput::~TextOutput() {
+}
+
+// ---------------------------------------------------------------------------
TextOutput& operator<<(TextOutput& to, bool val)
{
diff --git a/libs/utils/TimerProbe.cpp b/libs/utils/TimerProbe.cpp
deleted file mode 100644
index 835480d..0000000
--- a/libs/utils/TimerProbe.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <utils/TimerProbe.h>
-
-#if ENABLE_TIMER_PROBE
-
-#ifdef LOG_TAG
-#undef LOG_TAG
-#endif
-#define LOG_TAG "time"
-
-namespace android {
-
-Vector<TimerProbe::Bucket> TimerProbe::gBuckets;
-TimerProbe* TimerProbe::gExecuteChain;
-int TimerProbe::gIndent;
-timespec TimerProbe::gRealBase;
-
-TimerProbe::TimerProbe(const char tag[], int* slot) : mTag(tag)
-{
- mNext = gExecuteChain;
- gExecuteChain = this;
- mIndent = gIndent;
- gIndent += 1;
- if (mIndent > 0) {
- if (*slot == 0) {
- int count = gBuckets.add();
- *slot = count;
- Bucket& bucket = gBuckets.editItemAt(count);
- memset(&bucket, 0, sizeof(Bucket));
- bucket.mTag = tag;
- bucket.mSlotPtr = slot;
- bucket.mIndent = mIndent;
- }
- mBucket = *slot;
- }
- clock_gettime(CLOCK_REALTIME, &mRealStart);
- if (gRealBase.tv_sec == 0)
- gRealBase = mRealStart;
- clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &mPStart);
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &mTStart);
-}
-
-void TimerProbe::end()
-{
- timespec realEnd, pEnd, tEnd;
- clock_gettime(CLOCK_REALTIME, &realEnd);
- clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &pEnd);
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tEnd);
- print(realEnd, pEnd, tEnd);
- mTag = NULL;
-}
-
-TimerProbe::~TimerProbe()
-{
- if (mTag != NULL)
- end();
- gExecuteChain = mNext;
- gIndent--;
-}
-
-
-uint32_t TimerProbe::ElapsedTime(const timespec& start, const timespec& end)
-{
- int sec = end.tv_sec - start.tv_sec;
- int nsec = end.tv_nsec - start.tv_nsec;
- if (nsec < 0) {
- sec--;
- nsec += 1000000000;
- }
- return sec * 1000000 + nsec / 1000;
-}
-
-void TimerProbe::print(const timespec& r, const timespec& p,
- const timespec& t) const
-{
- uint32_t es = ElapsedTime(gRealBase, mRealStart);
- uint32_t er = ElapsedTime(mRealStart, r);
- uint32_t ep = ElapsedTime(mPStart, p);
- uint32_t et = ElapsedTime(mTStart, t);
- if (mIndent > 0) {
- Bucket& bucket = gBuckets.editItemAt(mBucket);
- if (bucket.mStart == 0)
- bucket.mStart = es;
- bucket.mReal += er;
- bucket.mProcess += ep;
- bucket.mThread += et;
- bucket.mCount++;
- return;
- }
- int index = 0;
- int buckets = gBuckets.size();
- int count = 1;
- const char* tag = mTag;
- int indent = mIndent;
- do {
- LOGD("%-30.30s: (%3d) %-5.*s time=%-10.3f real=%7dus process=%7dus (%3d%%) thread=%7dus (%3d%%)\n",
- tag, count, indent > 5 ? 5 : indent, "+++++", es / 1000000.0,
- er, ep, ep * 100 / er, et, et * 100 / er);
- if (index >= buckets)
- break;
- Bucket& bucket = gBuckets.editItemAt(index);
- count = bucket.mCount;
- es = bucket.mStart;
- er = bucket.mReal;
- ep = bucket.mProcess;
- et = bucket.mThread;
- tag = bucket.mTag;
- indent = bucket.mIndent;
- *bucket.mSlotPtr = 0;
- } while (++index); // always true
- gBuckets.clear();
-}
-
-}; // namespace android
-
-#endif
diff --git a/libs/utils/Timers.cpp b/libs/utils/Timers.cpp
index 2abc811..784f035 100644
--- a/libs/utils/Timers.cpp
+++ b/libs/utils/Timers.cpp
@@ -18,7 +18,6 @@
// Timer functions.
//
#include <utils/Timers.h>
-#include <utils/ported.h> // may need usleep
#include <utils/Log.h>
#include <stdlib.h>
@@ -54,130 +53,6 @@ nsecs_t systemTime(int clock)
#endif
}
-//#define MONITOR_USLEEP
-
-/*
- * Sleep long enough that we'll wake up "interval" milliseconds after
- * the previous snooze.
- *
- * The "nextTick" argument is updated on each call, and should be passed
- * in every time. Set its fields to zero on the first call.
- *
- * Returns the #of intervals we have overslept, which will be zero if we're
- * on time. [Currently just returns 0 or 1.]
- */
-int sleepForInterval(long interval, struct timeval* pNextTick)
-{
- struct timeval now;
- long long timeBeforeNext;
- long sleepTime = 0;
- bool overSlept = false;
- //int usleepBias = 0;
-
-#ifdef USLEEP_BIAS
- /*
- * Linux likes to add 9000ms or so.
- * [not using this for now]
- */
- //usleepBias = USLEEP_BIAS;
-#endif
-
- gettimeofday(&now, NULL);
-
- if (pNextTick->tv_sec == 0) {
- /* special-case for first time through */
- *pNextTick = now;
- sleepTime = interval;
- android::DurationTimer::addToTimeval(pNextTick, interval);
- } else {
- /*
- * Compute how much time there is before the next tick. If this
- * value is negative, we've run over. If we've run over a little
- * bit we can shorten the next frame to keep the pace steady, but
- * if we've dramatically overshot we need to re-sync.
- */
- timeBeforeNext = android::DurationTimer::subtractTimevals(pNextTick, &now);
- //printf("TOP: now=%ld.%ld next=%ld.%ld diff=%ld\n",
- // now.tv_sec, now.tv_usec, pNextTick->tv_sec, pNextTick->tv_usec,
- // (long) timeBeforeNext);
- if (timeBeforeNext < -interval) {
- /* way over */
- overSlept = true;
- sleepTime = 0;
- *pNextTick = now;
- } else if (timeBeforeNext <= 0) {
- /* slightly over, keep the pace steady */
- overSlept = true;
- sleepTime = 0;
- } else if (timeBeforeNext <= interval) {
- /* right on schedule */
- sleepTime = timeBeforeNext;
- } else if (timeBeforeNext > interval && timeBeforeNext <= 2*interval) {
- /* sleep call returned early; do a longer sleep this time */
- sleepTime = timeBeforeNext;
- } else if (timeBeforeNext > interval) {
- /* we went back in time -- somebody updated system clock? */
- /* (could also be a *seriously* broken usleep()) */
- LOG(LOG_DEBUG, "",
- " Impossible: timeBeforeNext = %ld\n", (long)timeBeforeNext);
- sleepTime = 0;
- *pNextTick = now;
- }
- android::DurationTimer::addToTimeval(pNextTick, interval);
- }
- //printf(" Before sleep: now=%ld.%ld next=%ld.%ld sleepTime=%ld\n",
- // now.tv_sec, now.tv_usec, pNextTick->tv_sec, pNextTick->tv_usec,
- // sleepTime);
-
- /*
- * Sleep for the designated period of time.
- *
- * Linux tends to sleep for longer than requested, often by 17-18ms.
- * MinGW tends to sleep for less than requested, by as much as 14ms,
- * but occasionally oversleeps for 40+ms (looks like some external
- * factors plus round-off on a 64Hz clock). Cygwin is pretty steady.
- *
- * If you start the MinGW version, and then launch the Cygwin version,
- * the MinGW clock becomes more erratic. Not entirely sure why.
- *
- * (There's a lot of stuff here; it's really just a usleep() call with
- * a bunch of instrumentation.)
- */
- if (sleepTime > 0) {
-#if defined(MONITOR_USLEEP)
- struct timeval before, after;
- long long actual;
-
- gettimeofday(&before, NULL);
- usleep((long) sleepTime);
- gettimeofday(&after, NULL);
-
- /* check usleep() accuracy; default Linux threads are pretty sloppy */
- actual = android::DurationTimer::subtractTimevals(&after, &before);
- if ((long) actual < sleepTime - 14000 /*(sleepTime/10)*/ ||
- (long) actual > sleepTime + 20000 /*(sleepTime/10)*/)
- {
- LOG(LOG_DEBUG, "", " Odd usleep: req=%ld, actual=%ld\n", sleepTime,
- (long) actual);
- }
-#else
-#ifdef HAVE_WIN32_THREADS
- Sleep( sleepTime/1000 );
-#else
- usleep((long) sleepTime);
-#endif
-#endif
- }
-
- //printf("slept %d\n", sleepTime);
-
- if (overSlept)
- return 1; // close enough
- else
- return 0;
-}
-
-
/*
* ===========================================================================
* DurationTimer
diff --git a/libs/utils/ported.cpp b/libs/utils/ported.cpp
deleted file mode 100644
index 656e46f..0000000
--- a/libs/utils/ported.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-//
-// Ports of standard functions that don't exist on a specific platform.
-//
-// Note these are NOT in the "android" namespace.
-//
-#include <utils/ported.h>
-
-#if defined(NEED_GETTIMEOFDAY) || defined(NEED_USLEEP)
-# include <sys/time.h>
-# include <windows.h>
-#endif
-
-
-#if defined(NEED_GETTIMEOFDAY)
-/*
- * Replacement gettimeofday() for Windows environments (primarily MinGW).
- *
- * Ignores "tz".
- */
-int gettimeofday(struct timeval* ptv, struct timezone* tz)
-{
- long long nsTime; // time in 100ns units since Jan 1 1601
- FILETIME ft;
-
- if (tz != NULL) {
- // oh well
- }
-
- ::GetSystemTimeAsFileTime(&ft);
- nsTime = (long long) ft.dwHighDateTime << 32 |
- (long long) ft.dwLowDateTime;
- // convert to time in usec since Jan 1 1970
- ptv->tv_usec = (long) ((nsTime / 10LL) % 1000000LL);
- ptv->tv_sec = (long) ((nsTime - 116444736000000000LL) / 10000000LL);
-
- return 0;
-}
-#endif
-
-#if defined(NEED_USLEEP)
-//
-// Replacement usleep for Windows environments (primarily MinGW).
-//
-void usleep(unsigned long usec)
-{
- // Win32 API function Sleep() takes milliseconds
- ::Sleep((usec + 500) / 1000);
-}
-#endif
-
-#if 0 //defined(NEED_PIPE)
-//
-// Replacement pipe() command for MinGW
-//
-// The _O_NOINHERIT flag sets bInheritHandle to FALSE in the
-// SecurityAttributes argument to CreatePipe(). This means the handles
-// aren't inherited when a new process is created. The examples I've seen
-// use it, possibly because there's a lot of junk going on behind the
-// scenes. (I'm assuming "process" and "thread" are different here, so
-// we should be okay spinning up a thread.) The recommended practice is
-// to dup() the descriptor you want the child to have.
-//
-// It appears that unnamed pipes can't do non-blocking ("overlapped") I/O.
-// You can't use select() either, since that only works on sockets. The
-// Windows API calls that are useful here all operate on a HANDLE, not
-// an integer file descriptor, and I don't think you can get there from
-// here. The "named pipe" stuff is insane.
-//
-int pipe(int filedes[2])
-{
- return _pipe(filedes, 0, _O_BINARY | _O_NOINHERIT);
-}
-#endif
-
-#if defined(NEED_SETENV)
-/*
- * MinGW lacks these. For now, just stub them out so the code compiles.
- */
-int setenv(const char* name, const char* value, int overwrite)
-{
- return 0;
-}
-void unsetenv(const char* name)
-{
-}
-char* getenv(const char* name)
-{
- return NULL;
-}
-#endif
diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java
index 53e46b7..2ce1273 100644
--- a/location/java/android/location/Geocoder.java
+++ b/location/java/android/location/Geocoder.java
@@ -36,11 +36,11 @@ import java.util.List;
* coordinate into a (partial) address. The amount of detail in a
* reverse geocoded location description may vary, for example one
* might contain the full street address of the closest building, while
- * another might contain only a city name and postal code.
+ * another might contain only a city name and postal code.
*
* The Geocoder class requires a backend service that is not included in
- * the core android framework. The Geocoder query methods will return an
- * empty list if there no backend service in the platform.
+ * the core android framework. The Geocoder query methods will return an
+ * empty list if there no backend service in the platform.
*/
public final class Geocoder {
private static final String TAG = "Geocoder";
diff --git a/location/java/com/android/internal/location/GpsXtraDownloader.java b/location/java/com/android/internal/location/GpsXtraDownloader.java
index 2a8be57..33ebce7 100644
--- a/location/java/com/android/internal/location/GpsXtraDownloader.java
+++ b/location/java/com/android/internal/location/GpsXtraDownloader.java
@@ -64,6 +64,7 @@ public class GpsXtraDownloader {
if (count == 0) {
Log.e(TAG, "No XTRA servers were specified in the GPS configuration");
+ return;
} else {
mXtraServers = new String[count];
count = 0;
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 3dd8563..c46f64e 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -307,10 +307,14 @@ public class MediaScanner
private boolean mDefaultRingtoneSet;
/** Whether the scanner has set a default sound for the notification ringtone. */
private boolean mDefaultNotificationSet;
+ /** Whether the scanner has set a default sound for the alarm ringtone. */
+ private boolean mDefaultAlarmSet;
/** The filename for the default sound for the ringer ringtone. */
private String mDefaultRingtoneFilename;
/** The filename for the default sound for the notification ringtone. */
private String mDefaultNotificationFilename;
+ /** The filename for the default sound for the alarm ringtone. */
+ private String mDefaultAlarmAlertFilename;
/**
* The prefix for system properties that define the default sound for
* ringtones. Concatenate the name of the setting from Settings
@@ -369,6 +373,8 @@ public class MediaScanner
+ Settings.System.RINGTONE);
mDefaultNotificationFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX
+ Settings.System.NOTIFICATION_SOUND);
+ mDefaultAlarmAlertFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX
+ + Settings.System.ALARM_ALERT);
}
private MyMediaScannerClient mClient = new MyMediaScannerClient();
@@ -748,6 +754,12 @@ public class MediaScanner
setSettingIfNotSet(Settings.System.RINGTONE, tableUri, rowId);
mDefaultRingtoneSet = true;
}
+ } else if (alarms && !mDefaultAlarmSet) {
+ if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) ||
+ doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) {
+ setSettingIfNotSet(Settings.System.ALARM_ALERT, tableUri, rowId);
+ mDefaultAlarmSet = true;
+ }
}
return result;
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 8f05cec..70d29d2 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -122,8 +122,9 @@ public class RingtoneManager {
* current ringtone, which will be used to show a checkmark next to the item
* for this {@link Uri}. If showing an item for "Default" (@see
* {@link #EXTRA_RINGTONE_SHOW_DEFAULT}), this can also be one of
- * {@link System#DEFAULT_RINGTONE_URI} or
- * {@link System#DEFAULT_NOTIFICATION_URI} to have the "Default" item
+ * {@link System#DEFAULT_RINGTONE_URI},
+ * {@link System#DEFAULT_NOTIFICATION_URI}, or
+ * {@link System#DEFAULT_ALARM_ALERT_URI} to have the "Default" item
* checked.
*
* @see #ACTION_RINGTONE_PICKER
@@ -134,8 +135,9 @@ public class RingtoneManager {
/**
* Given to the ringtone picker as a {@link Uri}. The {@link Uri} of the
* ringtone to play when the user attempts to preview the "Default"
- * ringtone. This can be one of {@link System#DEFAULT_RINGTONE_URI} or
- * {@link System#DEFAULT_NOTIFICATION_URI} to have the "Default" point to
+ * ringtone. This can be one of {@link System#DEFAULT_RINGTONE_URI},
+ * {@link System#DEFAULT_NOTIFICATION_URI}, or
+ * {@link System#DEFAULT_ALARM_ALERT_URI} to have the "Default" point to
* the current sound for the given default sound type. If you are showing a
* ringtone picker for some other type of sound, you are free to provide any
* {@link Uri} here.
@@ -163,8 +165,9 @@ public class RingtoneManager {
* <p>
* It will be one of:
* <li> the picked ringtone,
- * <li> a {@link Uri} that equals {@link System#DEFAULT_RINGTONE_URI} or
- * {@link System#DEFAULT_NOTIFICATION_URI} if the default was chosen,
+ * <li> a {@link Uri} that equals {@link System#DEFAULT_RINGTONE_URI},
+ * {@link System#DEFAULT_NOTIFICATION_URI}, or
+ * {@link System#DEFAULT_ALARM_ALERT_URI} if the default was chosen,
* <li> null if the "Silent" item was picked.
*
* @see #ACTION_RINGTONE_PICKER
@@ -624,7 +627,8 @@ public class RingtoneManager {
*
* @param context A context used for querying.
* @param type The type whose default sound should be returned. One of
- * {@link #TYPE_RINGTONE} or {@link #TYPE_NOTIFICATION}.
+ * {@link #TYPE_RINGTONE}, {@link #TYPE_NOTIFICATION}, or
+ * {@link #TYPE_ALARM}.
* @return A {@link Uri} pointing to the default sound for the sound type.
* @see #setActualDefaultRingtoneUri(Context, int, Uri)
*/
@@ -640,7 +644,8 @@ public class RingtoneManager {
*
* @param context A context used for querying.
* @param type The type whose default sound should be set. One of
- * {@link #TYPE_RINGTONE} or {@link #TYPE_NOTIFICATION}.
+ * {@link #TYPE_RINGTONE}, {@link #TYPE_NOTIFICATION}, or
+ * {@link #TYPE_ALARM}.
* @param ringtoneUri A {@link Uri} pointing to the default sound to set.
* @see #getActualDefaultRingtoneUri(Context, int)
*/
@@ -655,6 +660,8 @@ public class RingtoneManager {
return Settings.System.RINGTONE;
} else if ((type & TYPE_NOTIFICATION) != 0) {
return Settings.System.NOTIFICATION_SOUND;
+ } else if ((type & TYPE_ALARM) != 0) {
+ return Settings.System.ALARM_ALERT;
} else {
return null;
}
@@ -674,8 +681,9 @@ public class RingtoneManager {
* Returns the type of a default {@link Uri}.
*
* @param defaultRingtoneUri The default {@link Uri}. For example,
- * {@link System#DEFAULT_RINGTONE_URI} or
- * {@link System#DEFAULT_NOTIFICATION_URI}.
+ * {@link System#DEFAULT_RINGTONE_URI},
+ * {@link System#DEFAULT_NOTIFICATION_URI}, or
+ * {@link System#DEFAULT_ALARM_ALERT_URI}.
* @return The type of the defaultRingtoneUri, or -1.
*/
public static int getDefaultType(Uri defaultRingtoneUri) {
@@ -685,6 +693,8 @@ public class RingtoneManager {
return TYPE_RINGTONE;
} else if (defaultRingtoneUri.equals(Settings.System.DEFAULT_NOTIFICATION_URI)) {
return TYPE_NOTIFICATION;
+ } else if (defaultRingtoneUri.equals(Settings.System.DEFAULT_ALARM_ALERT_URI)) {
+ return TYPE_ALARM;
} else {
return -1;
}
@@ -704,6 +714,8 @@ public class RingtoneManager {
return Settings.System.DEFAULT_RINGTONE_URI;
} else if ((type & TYPE_NOTIFICATION) != 0) {
return Settings.System.DEFAULT_NOTIFICATION_URI;
+ } else if ((type & TYPE_ALARM) != 0) {
+ return Settings.System.DEFAULT_ALARM_ALERT_URI;
} else {
return null;
}
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 8ee0cbd..9552aa6 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -18,6 +18,7 @@ LOCAL_SHARED_LIBRARIES := \
libnativehelper \
libcutils \
libutils \
+ libbinder \
libmedia \
libsgl \
libui
diff --git a/media/jni/soundpool/Android.mk b/media/jni/soundpool/Android.mk
index 374ddeb..9ff2e24 100644
--- a/media/jni/soundpool/Android.mk
+++ b/media/jni/soundpool/Android.mk
@@ -9,6 +9,7 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
+ libbinder \
libandroid_runtime \
libnativehelper \
libmedia
diff --git a/media/libdrm/mobile2/include/rights/RoManager.h b/media/libdrm/mobile2/include/rights/RoManager.h
index cf398b3..71e9eef 100644
--- a/media/libdrm/mobile2/include/rights/RoManager.h
+++ b/media/libdrm/mobile2/include/rights/RoManager.h
@@ -64,12 +64,6 @@ public:
vector<Ro*> getAllRo();
/**
- * Get the private key of the device.
- * @return the private key.
- */
- const string& getDevicePrivateKey() const;
-
- /**
* Get ro which contained rights of specific content.
* @param contentID the specific id of content.
* @return NULL if not fount otherwise the related ro.
diff --git a/media/libdrm/mobile2/src/rights/RoManager.cpp b/media/libdrm/mobile2/src/rights/RoManager.cpp
index 848c2ba..a115d21 100644
--- a/media/libdrm/mobile2/src/rights/RoManager.cpp
+++ b/media/libdrm/mobile2/src/rights/RoManager.cpp
@@ -121,9 +121,3 @@ bool RoManager::checkRoInCache(const string& roID)
return true;
}
-/** see RoManager.h */
-const string& RoManager::getDevicePrivateKey() const
-{
- string pk;
- return pk;
-}
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 8020da2..806ef52 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -21,7 +21,7 @@ LOCAL_SRC_FILES:= \
JetPlayer.cpp
LOCAL_SHARED_LIBRARIES := \
- libui libcutils libutils libsonivox
+ libui libcutils libutils libbinder libsonivox
LOCAL_MODULE:= libmedia
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 4c8b02a..cf0965e 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -29,11 +29,11 @@
#include <media/AudioSystem.h>
#include <media/AudioRecord.h>
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <utils/Log.h>
-#include <utils/MemoryDealer.h>
-#include <utils/Parcel.h>
-#include <utils/IPCThreadState.h>
+#include <binder/MemoryDealer.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
#include <utils/Timers.h>
#include <cutils/atomic.h>
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index a21a7a4..86d0542 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -18,7 +18,7 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <media/AudioSystem.h>
#include <math.h>
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 289bd75..4a1b69e 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -32,9 +32,9 @@
#include <media/AudioTrack.h>
#include <utils/Log.h>
-#include <utils/MemoryDealer.h>
-#include <utils/Parcel.h>
-#include <utils/IPCThreadState.h>
+#include <binder/MemoryDealer.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
#include <utils/Timers.h>
#include <cutils/atomic.h>
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index eeaa54f..6fc0cb7 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -21,7 +21,7 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <media/IAudioFlinger.h>
@@ -353,12 +353,6 @@ IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnAudioFlinger::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp
index 9d00aef..75699b4 100644
--- a/media/libmedia/IAudioFlingerClient.cpp
+++ b/media/libmedia/IAudioFlingerClient.cpp
@@ -20,7 +20,7 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <media/IAudioFlingerClient.h>
@@ -51,12 +51,6 @@ IMPLEMENT_META_INTERFACE(AudioFlingerClient, "android.media.IAudioFlingerClient"
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnAudioFlingerClient::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
index 6e42dac..8fb5d3d 100644
--- a/media/libmedia/IAudioRecord.cpp
+++ b/media/libmedia/IAudioRecord.cpp
@@ -18,7 +18,7 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <media/IAudioRecord.h>
@@ -66,12 +66,6 @@ IMPLEMENT_META_INTERFACE(AudioRecord, "android.media.IAudioRecord");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnAudioRecord::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index abc202d..75b861b 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -18,7 +18,7 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <media/IAudioTrack.h>
@@ -91,12 +91,6 @@ IMPLEMENT_META_INTERFACE(AudioTrack, "android.media.IAudioTrack");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnAudioTrack::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index 85b5944..d16394f 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -17,7 +17,7 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <SkBitmap.h>
#include <media/IMediaMetadataRetriever.h>
@@ -130,12 +130,6 @@ IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.hardware.IMediaMetadat
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnMediaMetadataRetriever::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index f18765a..e1bed5f 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -18,7 +18,7 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <media/IMediaPlayer.h>
#include <ui/ISurface.h>
@@ -176,12 +176,6 @@ IMPLEMENT_META_INTERFACE(MediaPlayer, "android.hardware.IMediaPlayer");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnMediaPlayer::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/media/libmedia/IMediaPlayerClient.cpp b/media/libmedia/IMediaPlayerClient.cpp
index 65022cd..da4f7ef 100644
--- a/media/libmedia/IMediaPlayerClient.cpp
+++ b/media/libmedia/IMediaPlayerClient.cpp
@@ -16,8 +16,8 @@
*/
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
#include <media/IMediaPlayerClient.h>
@@ -50,12 +50,6 @@ IMPLEMENT_META_INTERFACE(MediaPlayerClient, "android.hardware.IMediaPlayerClient
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnMediaPlayerClient::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 370e3fb..84efc2a 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -17,9 +17,9 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <media/IMediaPlayerService.h>
#include <media/IMediaRecorder.h>
@@ -115,12 +115,6 @@ IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.hardware.IMediaPlayerServi
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnMediaPlayerService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 84d08c4..53b5aa3 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -18,7 +18,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "IMediaRecorder"
#include <utils/Log.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <ui/ISurface.h>
#include <ui/ICamera.h>
#include <media/IMediaPlayerClient.h>
@@ -268,12 +268,6 @@ IMPLEMENT_META_INTERFACE(MediaRecorder, "android.hardware.IMediaRecorder");
// ----------------------------------------------------------------------
-#define CHECK_INTERFACE(interface, data, reply) \
- do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
- LOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
status_t BnMediaRecorder::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index 09afc6c..d34a8ed 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -18,8 +18,8 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaMetadataRetriever"
-#include <utils/IServiceManager.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
#include <media/mediametadataretriever.h>
#include <media/IMediaPlayerService.h>
#include <utils/Log.h>
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 809316a..0f3eb70 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -24,13 +24,13 @@
#include <unistd.h>
#include <fcntl.h>
-#include <utils/IServiceManager.h>
-#include <utils/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
#include <media/mediaplayer.h>
#include <media/AudioTrack.h>
-#include <utils/MemoryBase.h>
+#include <binder/MemoryBase.h>
namespace android {
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 6b26faf..0a5df0d 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -20,7 +20,7 @@
#include <utils/Log.h>
#include <ui/Surface.h>
#include <media/mediarecorder.h>
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <utils/String8.h>
#include <media/IMediaPlayerService.h>
#include <media/IMediaRecorder.h>
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index f7f2490..0877142 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -20,6 +20,7 @@ endif
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
+ libbinder \
libvorbisidec \
libsonivox \
libopencore_player \
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 31eecac..a17e651 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -30,10 +30,10 @@
#include <cutils/atomic.h>
#include <android_runtime/ActivityManager.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
-#include <utils/MemoryHeapBase.h>
-#include <utils/MemoryBase.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
#include <cutils/properties.h>
#include <media/MediaPlayerInterface.h>
@@ -105,7 +105,11 @@ MediaPlayerService::~MediaPlayerService()
sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(pid_t pid)
{
+#ifndef NO_OPENCORE
sp<MediaRecorderClient> recorder = new MediaRecorderClient(pid);
+#else
+ sp<MediaRecorderClient> recorder = NULL;
+#endif
LOGV("Create new media recorder client from pid %d", pid);
return recorder;
}
@@ -532,10 +536,12 @@ static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
{
sp<MediaPlayerBase> p;
switch (playerType) {
+#ifndef NO_OPENCORE
case PV_PLAYER:
LOGV(" create PVPlayer");
p = new PVPlayer();
break;
+#endif
case SONIVOX_PLAYER:
LOGV(" create MidiFile");
p = new MidiFile();
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index f138886..5a296bf 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -18,7 +18,10 @@
#ifndef ANDROID_MEDIAPLAYERSERVICE_H
#define ANDROID_MEDIAPLAYERSERVICE_H
-#include <utils.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <ui/SurfaceComposerClient.h>
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 8bc410c..e54f20d 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -25,10 +25,10 @@
#include <string.h>
#include <cutils/atomic.h>
#include <android_runtime/ActivityManager.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
-#include <utils/MemoryHeapBase.h>
-#include <utils/MemoryBase.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
#include <media/PVMediaRecorder.h>
#include <utils/String16.h>
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index a320bd5..ba8d9a8 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -26,10 +26,10 @@
#include <string.h>
#include <cutils/atomic.h>
-#include <utils/MemoryDealer.h>
+#include <binder/MemoryDealer.h>
#include <android_runtime/ActivityManager.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <media/MediaMetadataRetrieverInterface.h>
#include <media/MediaPlayerInterface.h>
#include <media/PVMetadataRetriever.h>
@@ -49,7 +49,11 @@ MetadataRetrieverClient::MetadataRetrieverClient(pid_t pid)
mThumbnail = NULL;
mAlbumArt = NULL;
+#ifndef NO_OPENCORE
mRetriever = new PVMetadataRetriever();
+#else
+ mRetriever = NULL;
+#endif
if (mRetriever == NULL) {
LOGE("failed to initialize the retriever");
}
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index ce29c98..88d50bf 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -18,9 +18,12 @@
#ifndef ANDROID_MEDIAMETADATARETRIEVERSERVICE_H
#define ANDROID_MEDIAMETADATARETRIEVERSERVICE_H
-#include <utils.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <utils/KeyedVector.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <media/MediaMetadataRetrieverInterface.h>
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index c681698..a92cea8 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -8,7 +8,8 @@ LOCAL_SHARED_LIBRARIES := \
libaudioflinger \
libcameraservice \
libmediaplayerservice \
- libutils
+ libutils \
+ libbinder
base := $(LOCAL_PATH)/../..
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index 6954b63..fbea0d4 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -20,9 +20,9 @@
#include <unistd.h>
#include <grp.h>
-#include <utils/IPCThreadState.h>
-#include <utils/ProcessState.h>
-#include <utils/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <AudioFlinger.h>
diff --git a/media/sdutils/sdutil.cpp b/media/sdutils/sdutil.cpp
index a9aabf0..6f0cdfb 100644
--- a/media/sdutils/sdutil.cpp
+++ b/media/sdutils/sdutil.cpp
@@ -15,8 +15,8 @@
*/
#include <hardware_legacy/IMountService.h>
-#include <utils/BpBinder.h>
-#include <utils/IServiceManager.h>
+#include <binder/BpBinder.h>
+#include <binder/IServiceManager.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index 4a2f823..2ff0c9d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -47,7 +47,7 @@ import android.media.MediaMetadataRetriever;
*/
public class MediaPlayerPerformance extends ActivityInstrumentationTestCase<MediaFrameworkTest> {
- private String TAG = "MediaFrameworkPerformance";
+ private String TAG = "MediaPlayerPerformance";
private SQLiteDatabase mDB;
private SurfaceHolder mSurfaceHolder = null;
@@ -87,9 +87,11 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase<Medi
public void createDB() {
mDB = SQLiteDatabase.openOrCreateDatabase("/sdcard/perf.db", null);
- mDB.execSQL("CREATE TABLE perfdata (_id INTEGER PRIMARY KEY," +
+ mDB.execSQL("CREATE TABLE IF NOT EXISTS perfdata (_id INTEGER PRIMARY KEY," +
"file TEXT," + "setdatatime LONG," + "preparetime LONG," +
"playtime LONG" + ");");
+ //clean the table before adding new data
+ mDB.execSQL("DELETE FROM perfdata");
}
public void audioPlaybackStartupTime(String[] testFile) {
@@ -148,6 +150,10 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase<Medi
audioPlaybackStartupTime(MediaNames.MP3FILES);
audioPlaybackStartupTime(MediaNames.AACFILES);
+ //close the database after all transactions
+ if (mDB.isOpen()) {
+ mDB.close();
+ }
}
public void wmametadatautility(String[] testFile) {
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 23304d5..02dadbb 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -11,7 +11,7 @@ LOCAL_SRC_FILES:= \
EGL/gpu.cpp \
#
-LOCAL_SHARED_LIBRARIES += libcutils libutils libui
+LOCAL_SHARED_LIBRARIES += libcutils libutils libbinder libui
LOCAL_LDLIBS := -lpthread -ldl
LOCAL_MODULE:= libEGL
diff --git a/opengl/libs/EGL/gpu.cpp b/opengl/libs/EGL/gpu.cpp
index 4c902c8..416bd5d 100644
--- a/opengl/libs/EGL/gpu.cpp
+++ b/opengl/libs/EGL/gpu.cpp
@@ -29,11 +29,11 @@
#include <cutils/log.h>
#include <cutils/properties.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <utils/threads.h>
-#include <utils/IServiceManager.h>
-#include <utils/IPCThreadState.h>
-#include <utils/Parcel.h>
+#include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/Parcel.h>
#include <ui/EGLDisplaySurface.h>
#include <ui/ISurfaceComposer.h>
diff --git a/packages/SettingsProvider/etc/bookmarks.xml b/packages/SettingsProvider/etc/bookmarks.xml
index 5fb6608..33b4c97 100644
--- a/packages/SettingsProvider/etc/bookmarks.xml
+++ b/packages/SettingsProvider/etc/bookmarks.xml
@@ -39,10 +39,12 @@
package="com.android.calendar"
class="com.android.calendar.LaunchActivity"
shortcut="l" />
+<!--
<bookmark
package="com.google.android.apps.maps"
class="com.google.android.maps.MapsActivity"
shortcut="m" />
+-->
<bookmark
package="com.android.music"
class="com.android.music.MusicBrowserActivity"
@@ -55,4 +57,4 @@
package="com.google.android.youtube"
class="com.google.android.youtube.HomePage"
shortcut="y" />
-</bookmarks> \ No newline at end of file
+</bookmarks>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index f6958ed..57f8147 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -56,7 +56,7 @@ import java.util.List;
* Database helper class for {@link SettingsProvider}.
* Mostly just has a bit {@link #onCreate} to initialize the database.
*/
-class DatabaseHelper extends SQLiteOpenHelper {
+public class DatabaseHelper extends SQLiteOpenHelper {
/**
* Path to file containing default bookmarks, relative to ANDROID_ROOT.
*/
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 6f430c4..6d90001 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -43,7 +43,7 @@ public class SettingsProvider extends ContentProvider {
private static final String TABLE_FAVORITES = "favorites";
private static final String TABLE_OLD_FAVORITES = "old_favorites";
- private DatabaseHelper mOpenHelper;
+ protected DatabaseHelper mOpenHelper;
/**
* Decode a content URL into the table, projection, and arguments
diff --git a/packages/SubscribedFeedsProvider/AndroidManifest.xml b/packages/SubscribedFeedsProvider/AndroidManifest.xml
index 6ecda48..c254d93 100644
--- a/packages/SubscribedFeedsProvider/AndroidManifest.xml
+++ b/packages/SubscribedFeedsProvider/AndroidManifest.xml
@@ -19,7 +19,7 @@
android:writePermission="android.permission.SUBSCRIBED_FEEDS_WRITE" />
<receiver android:name="SubscribedFeedsBroadcastReceiver">
<intent-filter>
- <action android:name="android.intent.action.GTALK_DATA_MESSAGE_RECEIVED" />
+ <action android:name="android.intent.action.REMOTE_INTENT" />
<category android:name="GSYNC_TICKLE"/>
</intent-filter>
<intent-filter>
diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
index 8b3bedf..9992420 100644
--- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
@@ -19,10 +19,13 @@ import android.os.Bundle;
import android.os.RemoteException;
import android.text.TextUtils;
import android.net.Uri;
+import android.accounts.Account;
import java.util.ArrayList;
import java.util.Calendar;
+import com.google.android.collect.Lists;
+
/**
* A service to handle various intents asynchronously.
*/
@@ -30,7 +33,8 @@ public class SubscribedFeedsIntentService extends IntentService {
private static final String TAG = "Sync";
private static final String[] sAccountProjection =
- new String[] {SubscribedFeeds.Accounts._SYNC_ACCOUNT};
+ new String[] {SubscribedFeeds.Accounts._SYNC_ACCOUNT,
+ SubscribedFeeds.Accounts._SYNC_ACCOUNT_TYPE};
/** How often to refresh the subscriptions, in milliseconds */
private static final long SUBSCRIPTION_REFRESH_INTERVAL = 1000L * 60 * 60 * 24; // one day
@@ -39,8 +43,7 @@ public class SubscribedFeedsIntentService extends IntentService {
private static final String sSubscribedFeedsPrefs = "subscribedFeeds";
- private static final String GTALK_DATA_MESSAGE_RECEIVED =
- "android.intent.action.GTALK_DATA_MESSAGE_RECEIVED";
+ private static final String REMOTE_INTENT_ACTION = Intent.ACTION_REMOTE_INTENT;
private static final String SUBSCRIBED_FEEDS_REFRESH_ACTION =
"com.android.subscribedfeeds.action.REFRESH";
@@ -52,13 +55,14 @@ public class SubscribedFeedsIntentService extends IntentService {
}
protected void onHandleIntent(Intent intent) {
- if (GTALK_DATA_MESSAGE_RECEIVED.equals(intent.getAction())) {
- boolean fromTrustedServer = intent.getBooleanExtra("from_trusted_server", false);
+ if (REMOTE_INTENT_ACTION.equals(intent.getAction())) {
+ boolean fromTrustedServer = intent.getBooleanExtra(
+ "android.intent.extra.from_trusted_server", false);
if (fromTrustedServer) {
- String account = intent.getStringExtra("account");
- String token = intent.getStringExtra("message_token");
+ String accountName = intent.getStringExtra("account");
+ String token = intent.getStringExtra(Intent.EXTRA_REMOTE_INTENT_TOKEN);
- if (TextUtils.isEmpty(account) || TextUtils.isEmpty(token)) {
+ if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(token)) {
if (Config.LOGD) {
Log.d(TAG, "Ignoring malformed tickle -- missing account or token.");
}
@@ -67,10 +71,10 @@ public class SubscribedFeedsIntentService extends IntentService {
if (Config.LOGD) {
Log.d(TAG, "Received network tickle for "
- + account + " - " + token);
+ + accountName + " - " + token);
}
- handleTickle(this, account, token);
+ handleTickle(this, accountName, token);
} else {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Ignoring tickle -- not from trusted server.");
@@ -102,16 +106,18 @@ public class SubscribedFeedsIntentService extends IntentService {
alarmManager.set(AlarmManager.RTC, when, pendingIntent);
}
- private void handleTickle(Context context, String account, String feed) {
+ private void handleTickle(Context context, String accountName, String feed) {
Cursor c = null;
final String where = SubscribedFeeds.Feeds._SYNC_ACCOUNT + "= ? "
+ + "and " + SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "= ? "
+ "and " + SubscribedFeeds.Feeds.FEED + "= ?";
try {
+ // TODO(fredq) fix the hardcoded type
c = context.getContentResolver().query(SubscribedFeeds.Feeds.CONTENT_URI,
- null, where, new String[]{account, feed}, null);
+ null, where, new String[]{accountName, "com.google.GAIA", feed}, null);
if (c.getCount() == 0) {
Log.w(TAG, "received tickle for non-existent feed: "
- + "account " + account + ", feed " + feed);
+ + "account " + accountName + ", feed " + feed);
EventLog.writeEvent(LOG_TICKLE, "unknown");
}
while (c.moveToNext()) {
@@ -131,7 +137,8 @@ public class SubscribedFeedsIntentService extends IntentService {
}
Uri uri = Uri.parse("content://" + authority);
Bundle extras = new Bundle();
- extras.putString(ContentResolver.SYNC_EXTRAS_ACCOUNT, account);
+ extras.putParcelable(ContentResolver.SYNC_EXTRAS_ACCOUNT,
+ new Account(accountName, "com.google.GAIA"));
extras.putString("feed", feed);
context.getContentResolver().startSync(uri, extras);
}
@@ -150,31 +157,35 @@ public class SubscribedFeedsIntentService extends IntentService {
*/
private void handleRefreshAlarm(Context context) {
// retrieve the list of accounts from the subscribed feeds
- ArrayList<String> accounts = new ArrayList<String>();
+ ArrayList<Account> accounts = Lists.newArrayList();
ContentResolver contentResolver = context.getContentResolver();
Cursor c = contentResolver.query(SubscribedFeeds.Accounts.CONTENT_URI,
sAccountProjection, null, null, null);
- while (c.moveToNext()) {
- String account = c.getString(0);
- if (TextUtils.isEmpty(account)) {
- continue;
+ try {
+ while (c.moveToNext()) {
+ String accountName = c.getString(0);
+ String accountType = c.getString(1);
+ accounts.add(new Account(accountName, accountType));
}
- accounts.add(account);
+ } finally {
+ c.close();
}
- c.deactivate();
// Clear the auth tokens for all these accounts so that we are sure
// they will still be valid until the next time we refresh them.
- // TODO: add this when the google login service is done
+ // TODO(fredq): add this when the google login service is done
// mark the feeds dirty, by setting the accounts to the same value,
// which will trigger a sync.
try {
ContentValues values = new ContentValues();
- for (String account : accounts) {
- values.put(SyncConstValue._SYNC_ACCOUNT, account);
+ for (Account account : accounts) {
+ values.put(SyncConstValue._SYNC_ACCOUNT, account.mName);
+ values.put(SyncConstValue._SYNC_ACCOUNT_TYPE, account.mType);
contentResolver.update(SubscribedFeeds.Feeds.CONTENT_URI, values,
- SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=?", new String[] {account});
+ SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=? AND "
+ + SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "=?",
+ new String[] {account.mName, account.mType});
}
} catch (SQLiteFullException e) {
Log.w(TAG, "disk full while trying to mark the feeds as dirty, skipping");
diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java
index 9ecc3d6..d87f5e7 100644
--- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java
@@ -39,7 +39,7 @@ import java.util.HashMap;
public class SubscribedFeedsProvider extends AbstractSyncableContentProvider {
private static final String TAG = "SubscribedFeedsProvider";
private static final String DATABASE_NAME = "subscribedfeeds.db";
- private static final int DATABASE_VERSION = 10;
+ private static final int DATABASE_VERSION = 11;
private static final int FEEDS = 1;
private static final int FEED_ID = 2;
@@ -88,6 +88,7 @@ public class SubscribedFeedsProvider extends AbstractSyncableContentProvider {
db.execSQL("CREATE TABLE feeds (" +
"_id INTEGER PRIMARY KEY," +
"_sync_account TEXT," + // From the sync source
+ "_sync_account_type TEXT," + // From the sync source
"_sync_id TEXT," + // From the sync source
"_sync_time TEXT," + // From the sync source
"_sync_version TEXT," + // From the sync source
@@ -106,8 +107,8 @@ public class SubscribedFeedsProvider extends AbstractSyncableContentProvider {
"WHEN old._sync_id is not null " +
"BEGIN " +
"INSERT INTO _deleted_feeds " +
- "(_sync_id, _sync_account, _sync_version) " +
- "VALUES (old._sync_id, old._sync_account, " +
+ "(_sync_id, _sync_account, _sync_account_type, _sync_version) " +
+ "VALUES (old._sync_id, old._sync_account, old._sync_account_type, " +
"old._sync_version);" +
"END");
@@ -116,6 +117,7 @@ public class SubscribedFeedsProvider extends AbstractSyncableContentProvider {
"_sync_id TEXT," +
(isTemporary() ? "_sync_local_id INTEGER," : "") + // Used while syncing,
"_sync_account TEXT," +
+ "_sync_account_type TEXT," +
"_sync_mark INTEGER, " + // Used to filter out new rows
"UNIQUE(_sync_id))");
}
@@ -170,7 +172,8 @@ public class SubscribedFeedsProvider extends AbstractSyncableContentProvider {
qb.setDistinct(true);
qb.setProjectionMap(ACCOUNTS_PROJECTION_MAP);
return qb.query(getDatabase(), projection, selection, selectionArgs,
- SubscribedFeeds.Feeds._SYNC_ACCOUNT, null, sortOrder);
+ SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + ","
+ + SubscribedFeeds.Feeds._SYNC_ACCOUNT, null, sortOrder);
case FEED_ID:
qb.setTables(sFeedsTable);
qb.appendWhere(sFeedsTable + "._id=");
@@ -310,6 +313,8 @@ public class SubscribedFeedsProvider extends AbstractSyncableContentProvider {
DatabaseUtils.cursorStringToContentValues(diffsCursor,
SubscribedFeeds.Feeds._SYNC_ACCOUNT, mValues);
DatabaseUtils.cursorStringToContentValues(diffsCursor,
+ SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE, mValues);
+ DatabaseUtils.cursorStringToContentValues(diffsCursor,
SubscribedFeeds.Feeds._SYNC_VERSION, mValues);
db.replace(mDeletedTable, SubscribedFeeds.Feeds._SYNC_ID, mValues);
}
@@ -369,5 +374,7 @@ public class SubscribedFeedsProvider extends AbstractSyncableContentProvider {
ACCOUNTS_PROJECTION_MAP = map;
map.put(SubscribedFeeds.Accounts._COUNT, "COUNT(*) AS _count");
map.put(SubscribedFeeds.Accounts._SYNC_ACCOUNT, SubscribedFeeds.Accounts._SYNC_ACCOUNT);
+ map.put(SubscribedFeeds.Accounts._SYNC_ACCOUNT_TYPE,
+ SubscribedFeeds.Accounts._SYNC_ACCOUNT_TYPE);
}
}
diff --git a/preloaded-classes b/preloaded-classes
index 0520e41..3858883 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1,7 +1,5 @@
# Classes which are preloaded by com.android.internal.os.ZygoteInit.
android.R$styleable
-android.accounts.AccountMonitor
-android.accounts.AccountMonitor$AccountUpdater
android.app.Activity
android.app.ActivityGroup
android.app.ActivityManager$MemoryInfo$1
@@ -213,7 +211,6 @@ android.location.Location
android.media.AudioManager
android.media.IAudioService$Stub
android.media.IAudioService$Stub$Proxy
-android.media.MediaPlayer
android.net.LocalSocket
android.net.LocalSocketAddress
android.net.LocalSocketAddress$Namespace
@@ -488,7 +485,6 @@ android.webkit.HttpDateTime
android.webkit.JWebCoreJavaBridge
android.webkit.LoadListener
android.webkit.MimeTypeMap
-android.webkit.TextDialog
android.webkit.URLUtil
android.webkit.WebBackForwardList
android.webkit.WebHistoryItem
@@ -504,14 +500,14 @@ android.webkit.WebSettings$RenderPriority
android.webkit.WebSettings$TextSize
android.webkit.WebSyncManager
android.webkit.WebSyncManager$SyncHandler
+android.webkit.WebTextView
android.webkit.WebView
android.webkit.WebView$ExtendedZoomControls
-android.webkit.WebView$FocusNode
android.webkit.WebView$PrivateHandler
android.webkit.WebViewCore
+android.webkit.WebViewCore$CursorData
android.webkit.WebViewCore$EventHub
android.webkit.WebViewCore$EventHub$1
-android.webkit.WebViewCore$FocusData
android.webkit.WebViewCore$WebCoreThread
android.webkit.WebViewCore$WebCoreThread$1
android.webkit.WebViewDatabase
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index 90d8c9d..596053d 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -92,6 +92,8 @@ class BatteryService extends Binder {
// This should probably be exposed in the API, though it's not critical
private static final int BATTERY_PLUGGED_NONE = 0;
+ private static final int BATTERY_LEVEL_WARNING = 15;
+
private final Context mContext;
private final IBatteryStats mBatteryStats;
@@ -260,6 +262,18 @@ class BatteryService extends Binder {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcast(intent);
}
+
+ final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
+ final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
+
+ /* The ACTION_BATTERY_LOW broadcast is sent in these situations:
+ * - is just un-plugged (previously was plugged) and battery level is under WARNING, or
+ * - is not plugged and battery level crosses the WARNING boundary (becomes < 15).
+ */
+ final boolean sendBatteryLow = !plugged
+ && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
+ && mBatteryLevel < BATTERY_LEVEL_WARNING
+ && (oldPlugged || mLastBatteryLevel >= BATTERY_LEVEL_WARNING);
mLastBatteryStatus = mBatteryStatus;
mLastBatteryHealth = mBatteryHealth;
@@ -269,8 +283,11 @@ class BatteryService extends Binder {
mLastBatteryVoltage = mBatteryVoltage;
mLastBatteryTemperature = mBatteryTemperature;
mLastBatteryLevelCritical = mBatteryLevelCritical;
-
+
sendIntent();
+ if (sendBatteryLow) {
+ mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_LOW));
+ }
// This needs to be done after sendIntent() so that we get the lastest battery stats.
if (logOutlier && dischargeDuration != 0) {
diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java
index 7b8a2a4..9c1f942 100644
--- a/services/java/com/android/server/InputDevice.java
+++ b/services/java/com/android/server/InputDevice.java
@@ -63,7 +63,7 @@ public class InputDevice {
yMoveScale = my != 0 ? (1.0f/my) : 1.0f;
}
- MotionEvent generateMotion(InputDevice device, long curTime,
+ MotionEvent generateMotion(InputDevice device, long curTime, long curTimeNano,
boolean isAbs, Display display, int orientation,
int metaState) {
if (!changed) {
@@ -167,7 +167,7 @@ public class InputDevice {
if (!isAbs) {
x = y = 0;
}
- return MotionEvent.obtain(downTime, curTime, action,
+ return MotionEvent.obtainNano(downTime, curTime, curTimeNano, action,
scaledX, scaledY, scaledPressure, scaledSize, metaState,
xPrecision, yPrecision, device.id, edgeFlags);
} else {
@@ -181,7 +181,7 @@ public class InputDevice {
}
return null;
}
- MotionEvent me = MotionEvent.obtain(downTime, curTime,
+ MotionEvent me = MotionEvent.obtainNano(downTime, curTime, curTimeNano,
MotionEvent.ACTION_MOVE, scaledX, scaledY,
scaledPressure, scaledSize, metaState,
xPrecision, yPrecision, device.id, edgeFlags);
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index 411cd6b..78cdf8b 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -18,8 +18,9 @@ package com.android.server;
import android.content.Context;
import android.content.res.Configuration;
-import android.os.SystemClock;
+import android.os.LatencyTimer;
import android.os.PowerManager;
+import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;
import android.view.Display;
@@ -73,14 +74,17 @@ public abstract class KeyInputQueue {
public static final int FILTER_REMOVE = 0;
public static final int FILTER_KEEP = 1;
public static final int FILTER_ABORT = -1;
-
+
+ private static final boolean MEASURE_LATENCY = false;
+ private LatencyTimer lt;
+
public interface FilterCallback {
int filterEvent(QueuedEvent ev);
}
static class QueuedEvent {
InputDevice inputDevice;
- long when;
+ long whenNano;
int flags; // From the raw event
int classType; // One of the class constants in InputEvent
Object event;
@@ -88,7 +92,7 @@ public abstract class KeyInputQueue {
void copyFrom(QueuedEvent that) {
this.inputDevice = that.inputDevice;
- this.when = that.when;
+ this.whenNano = that.whenNano;
this.flags = that.flags;
this.classType = that.classType;
this.event = that.event;
@@ -107,6 +111,10 @@ public abstract class KeyInputQueue {
}
KeyInputQueue(Context context) {
+ if (MEASURE_LATENCY) {
+ lt = new LatencyTimer(100, 1000);
+ }
+
PowerManager pm = (PowerManager)context.getSystemService(
Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
@@ -241,7 +249,7 @@ public abstract class KeyInputQueue {
if (configChanged) {
synchronized (mFirst) {
- addLocked(di, SystemClock.uptimeMillis(), 0,
+ addLocked(di, System.nanoTime(), 0,
RawInputEvent.CLASS_CONFIGURATION_CHANGED,
null);
}
@@ -256,6 +264,7 @@ public abstract class KeyInputQueue {
// timebase as SystemClock.uptimeMillis().
//curTime = gotOne ? ev.when : SystemClock.uptimeMillis();
final long curTime = SystemClock.uptimeMillis();
+ final long curTimeNano = System.nanoTime();
//Log.i(TAG, "curTime=" + curTime + ", systemClock=" + SystemClock.uptimeMillis());
final int classes = di.classes;
@@ -276,7 +285,7 @@ public abstract class KeyInputQueue {
down = false;
}
int keycode = rotateKeyCodeLocked(ev.keycode);
- addLocked(di, curTime, ev.flags,
+ addLocked(di, curTimeNano, ev.flags,
RawInputEvent.CLASS_KEYBOARD,
newKeyEvent(di, di.mDownTime, curTime, down,
keycode, 0, scancode,
@@ -330,7 +339,7 @@ public abstract class KeyInputQueue {
}
MotionEvent me;
- me = di.mAbs.generateMotion(di, curTime, true,
+ me = di.mAbs.generateMotion(di, curTime, curTimeNano, true,
mDisplay, mOrientation, mGlobalMetaState);
if (false) Log.v(TAG, "Absolute: x=" + di.mAbs.x
+ " y=" + di.mAbs.y + " ev=" + me);
@@ -338,15 +347,15 @@ public abstract class KeyInputQueue {
if (WindowManagerPolicy.WATCH_POINTER) {
Log.i(TAG, "Enqueueing: " + me);
}
- addLocked(di, curTime, ev.flags,
+ addLocked(di, curTimeNano, ev.flags,
RawInputEvent.CLASS_TOUCHSCREEN, me);
}
- me = di.mRel.generateMotion(di, curTime, false,
+ me = di.mRel.generateMotion(di, curTime, curTimeNano, false,
mDisplay, mOrientation, mGlobalMetaState);
if (false) Log.v(TAG, "Relative: x=" + di.mRel.x
+ " y=" + di.mRel.y + " ev=" + me);
if (me != null) {
- addLocked(di, curTime, ev.flags,
+ addLocked(di, curTimeNano, ev.flags,
RawInputEvent.CLASS_TRACKBALL, me);
}
}
@@ -530,7 +539,7 @@ public abstract class KeyInputQueue {
}
}
- private QueuedEvent obtainLocked(InputDevice device, long when,
+ private QueuedEvent obtainLocked(InputDevice device, long whenNano,
int flags, int classType, Object event) {
QueuedEvent ev;
if (mCacheCount == 0) {
@@ -542,7 +551,7 @@ public abstract class KeyInputQueue {
mCacheCount--;
}
ev.inputDevice = device;
- ev.when = when;
+ ev.whenNano = whenNano;
ev.flags = flags;
ev.classType = classType;
ev.event = event;
@@ -561,13 +570,13 @@ public abstract class KeyInputQueue {
}
}
- private void addLocked(InputDevice device, long when, int flags,
+ private void addLocked(InputDevice device, long whenNano, int flags,
int classType, Object event) {
boolean poke = mFirst.next == mLast;
- QueuedEvent ev = obtainLocked(device, when, flags, classType, event);
+ QueuedEvent ev = obtainLocked(device, whenNano, flags, classType, event);
QueuedEvent p = mLast.prev;
- while (p != mFirst && ev.when < p.when) {
+ while (p != mFirst && ev.whenNano < p.whenNano) {
p = p.prev;
}
@@ -578,8 +587,15 @@ public abstract class KeyInputQueue {
ev.inQueue = true;
if (poke) {
+ long time;
+ if (MEASURE_LATENCY) {
+ time = System.nanoTime();
+ }
mFirst.notify();
mWakeLock.acquire();
+ if (MEASURE_LATENCY) {
+ lt.sample("1 addLocked-queued event ", System.nanoTime() - time);
+ }
}
}
diff --git a/services/java/com/android/server/MasterClearReceiver.java b/services/java/com/android/server/MasterClearReceiver.java
index 5a42e76..3c366da 100644
--- a/services/java/com/android/server/MasterClearReceiver.java
+++ b/services/java/com/android/server/MasterClearReceiver.java
@@ -30,8 +30,8 @@ public class MasterClearReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals("android.intent.action.GTALK_DATA_MESSAGE_RECEIVED")) {
- if (!intent.getBooleanExtra("from_trusted_server", false)) {
+ if (intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) {
+ if (!intent.getBooleanExtra("android.intent.extra.from_trusted_server", false)) {
Log.w(TAG, "Ignoring master clear request -- not from trusted server.");
return;
}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 6a2e62f..dcc3ed5 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -1644,6 +1644,9 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
+ /**
+ * @deprecated
+ */
public void querySyncProviders(List outNames, List outInfo) {
synchronized (mPackages) {
Iterator<Map.Entry<String, PackageParser.Provider>> i
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index f6c1525..c82b49a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -32,12 +32,7 @@ import android.content.pm.IPackageManager;
import android.database.ContentObserver;
import android.database.Cursor;
import android.media.AudioService;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.SystemProperties;
+import android.os.*;
import android.provider.Contacts.People;
import android.provider.Settings;
import android.server.BluetoothA2dpService;
@@ -45,6 +40,7 @@ import android.server.BluetoothDeviceService;
import android.server.search.SearchManagerService;
import android.util.EventLog;
import android.util.Log;
+import android.accounts.AccountManagerService;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@@ -117,6 +113,14 @@ class ServerThread extends Thread {
mContentResolver = context.getContentResolver();
+ try {
+ Log.i(TAG, "Starting Account Manager.");
+ ServiceManager.addService(Context.ACCOUNT_SERVICE,
+ new AccountManagerService(context));
+ } catch (Throwable e) {
+ Log.e(TAG, "Failure starting Account Manager", e);
+ }
+
Log.i(TAG, "Starting Content Manager.");
ContentService.main(context,
factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL);
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 5df88b2..969fbfe 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -1443,14 +1443,17 @@ public class WifiService extends IWifiManager.Stub {
* Set the number of radio frequency channels that are allowed to be used
* in the current regulatory domain. This method should be used only
* if the correct number of channels cannot be determined automatically
- * for some reason. If the operation is successful, the new value is
+ * for some reason. If the operation is successful, the new value may be
* persisted as a Secure setting.
* @param numChannels the number of allowed channels. Must be greater than 0
* and less than or equal to 16.
+ * @param persist {@code true} if the setting should be remembered.
* @return {@code true} if the operation succeeds, {@code false} otherwise, e.g.,
* {@code numChannels} is outside the valid range.
*/
- public boolean setNumAllowedChannels(int numChannels) {
+ public boolean setNumAllowedChannels(int numChannels, boolean persist) {
+ Log.i(TAG, "WifiService trying to setNumAllowed to "+numChannels+
+ " with persist set to "+persist);
enforceChangePermission();
/*
* Validate the argument. We'd like to let the Wi-Fi driver do this,
@@ -1469,9 +1472,11 @@ public class WifiService extends IWifiManager.Stub {
return false;
}
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
- numChannels);
+ if (persist) {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
+ numChannels);
+ }
mWifiStateTracker.setNumAllowedChannels(numChannels);
return true;
}
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index a04d73a..4561e1a 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -63,6 +63,7 @@ import android.os.Binder;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
+import android.os.LatencyTimer;
import android.os.LocalPowerManager;
import android.os.Looper;
import android.os.Message;
@@ -133,7 +134,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_REORDER = false;
static final boolean SHOW_TRANSACTIONS = false;
-
+ static final boolean MEASURE_LATENCY = false;
+ static private LatencyTimer lt;
+
static final boolean PROFILE_ORIENTATION = false;
static final boolean BLUR = true;
static final boolean localLOGV = DEBUG;
@@ -495,6 +498,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
private WindowManagerService(Context context, PowerManagerService pm,
boolean haveInputMethods) {
+ if (MEASURE_LATENCY) {
+ lt = new LatencyTimer(100, 1000);
+ }
+
mContext = context;
mHaveInputMethods = haveInputMethods;
mLimitedAlphaCompositing = context.getResources().getBoolean(
@@ -3714,7 +3721,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
private final void wakeupIfNeeded(WindowState targetWin, int eventType) {
long curTime = SystemClock.uptimeMillis();
- if (eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT) {
+ if (eventType == TOUCH_EVENT || eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT) {
if (mLastTouchEventType == eventType &&
(curTime - mLastUserActivityCallTime) < MIN_TIME_BETWEEN_USERACTIVITIES) {
return;
@@ -3774,9 +3781,17 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (DEBUG_INPUT || WindowManagerPolicy.WATCH_POINTER) Log.v(TAG,
"dispatchPointer " + ev);
+ if (MEASURE_LATENCY) {
+ lt.sample("3 Wait for last dispatch ", System.nanoTime() - qev.whenNano);
+ }
+
Object targetObj = mKeyWaiter.waitForNextEventTarget(null, qev,
ev, true, false);
+ if (MEASURE_LATENCY) {
+ lt.sample("3 Last dispatch finished ", System.nanoTime() - qev.whenNano);
+ }
+
int action = ev.getAction();
if (action == MotionEvent.ACTION_UP) {
@@ -3813,6 +3828,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
WindowState target = (WindowState)targetObj;
final long eventTime = ev.getEventTime();
+ final long eventTimeNano = ev.getEventTimeNano();
//Log.i(TAG, "Sending " + ev + " to " + target);
@@ -3831,6 +3847,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
+ if (MEASURE_LATENCY) {
+ lt.sample("4 in dispatchPointer ", System.nanoTime() - eventTimeNano);
+ }
+
if ((target.mAttrs.flags &
WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) {
//target wants to ignore fat touch events
@@ -3913,6 +3933,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
+ if (MEASURE_LATENCY) {
+ lt.sample("5 in dispatchPointer ", System.nanoTime() - eventTimeNano);
+ }
+
synchronized(mWindowMap) {
if (qev != null && action == MotionEvent.ACTION_MOVE) {
mKeyWaiter.bindTargetWindowLocked(target,
@@ -3950,7 +3974,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (DEBUG_INPUT || DEBUG_FOCUS || WindowManagerPolicy.WATCH_POINTER) {
Log.v(TAG, "Delivering pointer " + qev + " to " + target);
}
+
+ if (MEASURE_LATENCY) {
+ lt.sample("6 before svr->client ipc ", System.nanoTime() - eventTimeNano);
+ }
+
target.mClient.dispatchPointer(ev, eventTime);
+
+ if (MEASURE_LATENCY) {
+ lt.sample("7 after svr->client ipc ", System.nanoTime() - eventTimeNano);
+ }
return true;
} catch (android.os.RemoteException e) {
Log.i(TAG, "WINDOW DIED during motion dispatch: " + target);
@@ -5071,7 +5104,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
- };
+ }
public boolean detectSafeMode() {
mSafeMode = mPolicy.detectSafeMode();
@@ -5136,9 +5169,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (DEBUG_INPUT && ev != null) Log.v(
TAG, "Event: type=" + ev.classType + " data=" + ev.event);
+ if (MEASURE_LATENCY) {
+ lt.sample("2 got event ", System.nanoTime() - ev.whenNano);
+ }
+
try {
if (ev != null) {
- curTime = ev.when;
+ curTime = SystemClock.uptimeMillis();
int eventType;
if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {
eventType = eventType((MotionEvent)ev.event);
@@ -5149,17 +5186,29 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
eventType = LocalPowerManager.OTHER_EVENT;
}
try {
- long now = SystemClock.uptimeMillis();
-
- if ((now - mLastBatteryStatsCallTime)
+ if ((curTime - mLastBatteryStatsCallTime)
>= MIN_TIME_BETWEEN_USERACTIVITIES) {
- mLastBatteryStatsCallTime = now;
+ mLastBatteryStatsCallTime = curTime;
mBatteryStats.noteInputEvent();
}
} catch (RemoteException e) {
// Ignore
}
- mPowerManager.userActivity(curTime, false, eventType, false);
+
+ if (eventType != TOUCH_EVENT
+ && eventType != LONG_TOUCH_EVENT
+ && eventType != CHEEK_EVENT) {
+ mPowerManager.userActivity(curTime, false,
+ eventType, false);
+ } else if (mLastTouchEventType != eventType
+ || (curTime - mLastUserActivityCallTime)
+ >= MIN_TIME_BETWEEN_USERACTIVITIES) {
+ mLastUserActivityCallTime = curTime;
+ mLastTouchEventType = eventType;
+ mPowerManager.userActivity(curTime, false,
+ eventType, false);
+ }
+
switch (ev.classType) {
case RawInputEvent.CLASS_KEYBOARD:
KeyEvent ke = (KeyEvent)ev.event;
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index 42c885d..b59fe54 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -80,10 +80,7 @@ public class StatusBarPolicy {
private static final int EVENT_DATA_ACTIVITY = 3;
private static final int EVENT_BATTERY_CLOSE = 4;
- // indices into mBatteryThresholds
- private static final int BATTERY_THRESHOLD_CLOSE_WARNING = 0;
- private static final int BATTERY_THRESHOLD_WARNING = 1;
- private static final int BATTERY_THRESHOLD_EMPTY = 2;
+ private static final int BATTERY_LEVEL_CLOSE_WARNING = 20;
private final Context mContext;
private final StatusBarService mService;
@@ -101,8 +98,6 @@ public class StatusBarPolicy {
private boolean mBatteryFirst = true;
private boolean mBatteryPlugged;
private int mBatteryLevel;
- private int mBatteryThreshold = 0; // index into mBatteryThresholds
- private int[] mBatteryThresholds = new int[] { 20, 15, -1 };
private AlertDialog mLowBatteryDialog;
private TextView mBatteryLevelTextView;
private View mBatteryView;
@@ -379,6 +374,9 @@ public class StatusBarPolicy {
else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
updateBattery(intent);
}
+ else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
+ onBatteryLow(intent);
+ }
else if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION) ||
action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) ||
action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
@@ -520,6 +518,7 @@ public class StatusBarPolicy {
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ filter.addAction(Intent.ACTION_BATTERY_LOW);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
filter.addAction(Intent.ACTION_ALARM_CHANGED);
filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
@@ -563,19 +562,6 @@ public class StatusBarPolicy {
//mService.setIconVisibility(mSyncFailingIcon, isFailing && !isActive);
}
- private void pickNextBatteryLevel(int level) {
- final int N = mBatteryThresholds.length;
- for (int i=0; i<N; i++) {
- if (level >= mBatteryThresholds[i]) {
- mBatteryThreshold = i;
- break;
- }
- }
- if (mBatteryThreshold >= N) {
- mBatteryThreshold = N-1;
- }
- }
-
private final void updateBattery(Intent intent) {
mBatteryData.iconId = intent.getIntExtra("icon-small", 0);
mBatteryData.iconLevel = intent.getIntExtra("level", 0);
@@ -588,13 +574,10 @@ public class StatusBarPolicy {
+ " plugged=" + plugged
+ " mBatteryPlugged=" + mBatteryPlugged
+ " mBatteryLevel=" + mBatteryLevel
- + " mBatteryThreshold=" + mBatteryThreshold
+ " mBatteryFirst=" + mBatteryFirst);
}
boolean oldPlugged = mBatteryPlugged;
- int oldThreshold = mBatteryThreshold;
- pickNextBatteryLevel(level);
mBatteryPlugged = plugged;
mBatteryLevel = level;
@@ -616,35 +599,29 @@ public class StatusBarPolicy {
}
*/
if (false) {
- Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level
- + " mBatteryThreshold=" + mBatteryThreshold + " oldThreshold=" + oldThreshold);
+ Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level);
}
- if (!plugged
- && ((oldPlugged && level < mBatteryThresholds[BATTERY_THRESHOLD_WARNING])
- || (mBatteryThreshold > oldThreshold
- && mBatteryThreshold > BATTERY_THRESHOLD_WARNING))) {
- // Broadcast the low battery warning
- mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_LOW));
-
- if (SHOW_LOW_BATTERY_WARNING) {
- if (false) {
- Log.d(TAG, "mPhoneState=" + mPhoneState
- + " mLowBatteryDialog=" + mLowBatteryDialog
- + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
- }
- if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
- showLowBatteryWarning();
- } else {
- mBatteryShowLowOnEndCall = true;
- }
+ if (mLowBatteryDialog != null
+ && mBatteryLevel >= BATTERY_LEVEL_CLOSE_WARNING
+ && SHOW_LOW_BATTERY_WARNING) {
+ mLowBatteryDialog.dismiss();
+ mBatteryShowLowOnEndCall = false;
+ }
+ }
+
+ private void onBatteryLow(Intent intent) {
+ if (SHOW_LOW_BATTERY_WARNING) {
+ if (false) {
+ Log.d(TAG, "mPhoneState=" + mPhoneState
+ + " mLowBatteryDialog=" + mLowBatteryDialog
+ + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
}
- } else if (mBatteryThreshold == BATTERY_THRESHOLD_CLOSE_WARNING) {
- if (SHOW_LOW_BATTERY_WARNING) {
- if (mLowBatteryDialog != null) {
- mLowBatteryDialog.dismiss();
- mBatteryShowLowOnEndCall = false;
- }
+
+ if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
+ showLowBatteryWarning();
+ } else {
+ mBatteryShowLowOnEndCall = true;
}
}
}
@@ -710,9 +687,11 @@ public class StatusBarPolicy {
private void showLowBatteryWarning() {
closeLastBatteryView();
- int level = mBatteryThresholds[mBatteryThreshold > 1 ? mBatteryThreshold - 1 : 0];
+ /* Show exact battery level.
+ * Add 1 because the text says "less than X%".
+ */
CharSequence levelText = mContext.getString(
- com.android.internal.R.string.battery_low_percent_format, level);
+ com.android.internal.R.string.battery_low_percent_format, mBatteryLevel + 1);
if (mBatteryLevelTextView != null) {
mBatteryLevelTextView.setText(levelText);
diff --git a/services/jni/com_android_server_AlarmManagerService.cpp b/services/jni/com_android_server_AlarmManagerService.cpp
index 1d66fb1..85d63c9 100644
--- a/services/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/jni/com_android_server_AlarmManagerService.cpp
@@ -19,8 +19,8 @@
#include "JNIHelp.h"
#include "jni.h"
-#include "utils/Log.h"
-#include "utils/misc.h"
+#include <utils/Log.h>
+#include <utils/misc.h>
#include <fcntl.h>
#include <stdio.h>
diff --git a/services/jni/com_android_server_BatteryService.cpp b/services/jni/com_android_server_BatteryService.cpp
index 2524966..e4f001f 100644
--- a/services/jni/com_android_server_BatteryService.cpp
+++ b/services/jni/com_android_server_BatteryService.cpp
@@ -18,8 +18,8 @@
#include "JNIHelp.h"
#include "jni.h"
-#include "utils/Log.h"
-#include "utils/misc.h"
+#include <utils/Log.h>
+#include <utils/misc.h>
#include <fcntl.h>
#include <stdio.h>
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index d3942fc..77669c3 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1003,6 +1003,7 @@ public class PhoneNumberUtils
* as:
*
* <p><code>
+ * xxxxx
* xxx-xxxx
* xxx-xxx-xxxx
* 1-xxx-xxx-xxxx
@@ -1016,7 +1017,11 @@ public class PhoneNumberUtils
if (length > "+1-nnn-nnn-nnnn".length()) {
// The string is too long to be formatted
return;
+ } else if (length <= 5) {
+ // The string is either a shortcode or too short to be formatted
+ return;
}
+
CharSequence saved = text.subSequence(0, length);
// Strip the dashes first, as we're going to add them back
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index d6b2737..c92cf3d 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -21,6 +21,7 @@ import android.app.IActivityManager;
import android.content.Context;
import android.content.res.Configuration;
import android.content.SharedPreferences;
+import android.net.wifi.WifiManager;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Looper;
@@ -28,6 +29,7 @@ import android.os.Message;
import android.os.RegistrantList;
import android.os.SystemProperties;
import android.preference.PreferenceManager;
+import android.provider.Settings;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.text.TextUtils;
@@ -185,7 +187,7 @@ public abstract class PhoneBase implements Phone {
this.mContext = context;
mLooper = Looper.myLooper();
- setLocaleByCarrier();
+ setPropertiesByCarrier();
setUnitTestMode(unitTestMode);
@@ -450,10 +452,10 @@ public abstract class PhoneBase implements Phone {
}
/**
- * Set the locale by matching the carrier string in
+ * Set the properties by matching the carrier string in
* a string-array resource
*/
- private void setLocaleByCarrier() {
+ private void setPropertiesByCarrier() {
String carrier = SystemProperties.get("ro.carrier");
if (null == carrier || 0 == carrier.length()) {
@@ -461,18 +463,36 @@ public abstract class PhoneBase implements Phone {
}
CharSequence[] carrierLocales = mContext.
- getResources().getTextArray(R.array.carrier_locales);
+ getResources().getTextArray(R.array.carrier_properties);
- for (int i = 0; i < carrierLocales.length-1; i+=2) {
+ for (int i = 0; i < carrierLocales.length; i+=3) {
String c = carrierLocales[i].toString();
- String l = carrierLocales[i+1].toString();
if (carrier.equals(c)) {
+ String l = carrierLocales[i+1].toString();
+ int wifiChannels = 0;
+ try {
+ wifiChannels = Integer.parseInt(
+ carrierLocales[i+2].toString());
+ } catch (NumberFormatException e) { }
+
String language = l.substring(0, 2);
String country = "";
if (l.length() >=5) {
country = l.substring(3, 5);
}
setSystemLocale(language, country);
+
+ if (wifiChannels != 0) {
+ try {
+ Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS);
+ } catch (Settings.SettingNotFoundException e) {
+ // note this is not persisting
+ WifiManager wM = (WifiManager)
+ mContext.getSystemService(Context.WIFI_SERVICE);
+ wM.setNumAllowedChannels(wifiChannels, false);
+ }
+ }
return;
}
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/MccTable.java b/telephony/java/com/android/internal/telephony/gsm/MccTable.java
index e18da56..22b1f4f 100644
--- a/telephony/java/com/android/internal/telephony/gsm/MccTable.java
+++ b/telephony/java/com/android/internal/telephony/gsm/MccTable.java
@@ -35,6 +35,7 @@ public final class MccTable
int smallestDigitsMnc;
String timezone;
String language;
+ int wifiChannelsAllowed;
MccEntry(int mnc, String iso, int smallestDigitsMCC) {
this(mnc, iso, smallestDigitsMCC, null);
@@ -45,11 +46,16 @@ public final class MccTable
}
MccEntry(int mnc, String iso, int smallestDigitsMCC, String timezone, String language) {
+ this(mnc, iso, smallestDigitsMCC, timezone, language, 0);
+ }
+
+ MccEntry(int mnc, String iso, int smallestDigitsMCC, String timezone, String language, int wifiChannels) {
this.mcc = mnc;
this.iso = iso;
this.smallestDigitsMnc = smallestDigitsMCC;
this.timezone = timezone;
this.language = language;
+ this.wifiChannelsAllowed = wifiChannels;
}
public int compareTo(MccEntry o)
@@ -148,6 +154,23 @@ public final class MccTable
}
}
+ /**
+ * Given a GSM Mobile Country Code, returns
+ * the number of wifi channels allowed in that country.
+ * Returns 0 if unavailable
+ */
+ public static int wifiChannelsForMcc(int mcc) {
+ MccEntry entry;
+
+ entry = entryForMcc(mcc);
+
+ if (entry == null) {
+ return 0;
+ } else {
+ return entry.wifiChannelsAllowed;
+ }
+ }
+
static {
table = new ArrayList<MccEntry>(240);
@@ -169,7 +192,7 @@ public final class MccTable
*/
table.add(new MccEntry(202,"gr",2)); //Greece
- table.add(new MccEntry(204,"nl",2,"Europe/Amsterdam","nl")); //Netherlands (Kingdom of the)
+ table.add(new MccEntry(204,"nl",2,"Europe/Amsterdam","nl",13)); //Netherlands (Kingdom of the)
table.add(new MccEntry(206,"be",2)); //Belgium
table.add(new MccEntry(208,"fr",2,"Europe/Paris","fr")); //France
table.add(new MccEntry(212,"mc",2)); //Monaco (Principality of)
@@ -183,11 +206,11 @@ public final class MccTable
table.add(new MccEntry(225,"va",2,"Europe/Rome","it")); //Vatican City State
table.add(new MccEntry(226,"ro",2)); //Romania
table.add(new MccEntry(228,"ch",2,"Europe/Zurich","de")); //Switzerland (Confederation of)
- table.add(new MccEntry(230,"cz",2,"Europe/Prague","cs")); //Czech Republic
+ table.add(new MccEntry(230,"cz",2,"Europe/Prague","cs", 13)); //Czech Republic
table.add(new MccEntry(231,"sk",2)); //Slovak Republic
- table.add(new MccEntry(232,"at",2,"Europe/Vienna","de")); //Austria
- table.add(new MccEntry(234,"gb",2,"Europe/London","en")); //United Kingdom of Great Britain and Northern Ireland
- table.add(new MccEntry(235,"gb",2,"Europe/London","en")); //United Kingdom of Great Britain and Northern Ireland
+ table.add(new MccEntry(232,"at",2,"Europe/Vienna","de", 13)); //Austria
+ table.add(new MccEntry(234,"gb",2,"Europe/London","en", 13)); //United Kingdom of Great Britain and Northern Ireland
+ table.add(new MccEntry(235,"gb",2,"Europe/London","en", 13)); //United Kingdom of Great Britain and Northern Ireland
table.add(new MccEntry(238,"dk",2)); //Denmark
table.add(new MccEntry(240,"se",2)); //Sweden
table.add(new MccEntry(242,"no",2)); //Norway
@@ -200,7 +223,7 @@ public final class MccTable
table.add(new MccEntry(257,"by",2)); //Belarus (Republic of)
table.add(new MccEntry(259,"md",2)); //Moldova (Republic of)
table.add(new MccEntry(260,"pl",2,"Europe/Warsaw")); //Poland (Republic of)
- table.add(new MccEntry(262,"de",2,"Europe/Berlin","de")); //Germany (Federal Republic of)
+ table.add(new MccEntry(262,"de",2,"Europe/Berlin","de", 13)); //Germany (Federal Republic of)
table.add(new MccEntry(266,"gi",2)); //Gibraltar
table.add(new MccEntry(268,"pt",2)); //Portugal
table.add(new MccEntry(270,"lu",2)); //Luxembourg
@@ -219,15 +242,15 @@ public final class MccTable
table.add(new MccEntry(293,"sl",2)); //Slovenia (Republic of)
table.add(new MccEntry(294,"mk",2)); //The Former Yugoslav Republic of Macedonia
table.add(new MccEntry(295,"li",2)); //Liechtenstein (Principality of)
- table.add(new MccEntry(302,"ca",2)); //Canada
+ table.add(new MccEntry(302,"ca",2, "", "", 11)); //Canada
table.add(new MccEntry(308,"pm",2)); //Saint Pierre and Miquelon (Collectivit territoriale de la Rpublique franaise)
- table.add(new MccEntry(310,"us",3,"","en")); //United States of America
- table.add(new MccEntry(311,"us",3,"","en")); //United States of America
- table.add(new MccEntry(312,"us",3,"","en")); //United States of America
- table.add(new MccEntry(313,"us",3,"","en")); //United States of America
- table.add(new MccEntry(314,"us",3,"","en")); //United States of America
- table.add(new MccEntry(315,"us",3,"","en")); //United States of America
- table.add(new MccEntry(316,"us",3,"","en")); //United States of America
+ table.add(new MccEntry(310,"us",3,"","en", 11)); //United States of America
+ table.add(new MccEntry(311,"us",3,"","en", 11)); //United States of America
+ table.add(new MccEntry(312,"us",3,"","en", 11)); //United States of America
+ table.add(new MccEntry(313,"us",3,"","en", 11)); //United States of America
+ table.add(new MccEntry(314,"us",3,"","en", 11)); //United States of America
+ table.add(new MccEntry(315,"us",3,"","en", 11)); //United States of America
+ table.add(new MccEntry(316,"us",3,"","en", 11)); //United States of America
table.add(new MccEntry(330,"pr",2)); //Puerto Rico
table.add(new MccEntry(332,"vi",2)); //United States Virgin Islands
table.add(new MccEntry(334,"mx",3)); //Mexico
@@ -283,8 +306,8 @@ public final class MccTable
table.add(new MccEntry(436,"tj",2)); //Tajikistan (Republic of)
table.add(new MccEntry(437,"kg",2)); //Kyrgyz Republic
table.add(new MccEntry(438,"tm",2)); //Turkmenistan
- table.add(new MccEntry(440,"jp",2,"Asia/Tokyo","ja")); //Japan
- table.add(new MccEntry(441,"jp",2,"Asia/Tokyo","ja")); //Japan
+ table.add(new MccEntry(440,"jp",2,"Asia/Tokyo","ja", 14)); //Japan
+ table.add(new MccEntry(441,"jp",2,"Asia/Tokyo","ja", 14)); //Japan
table.add(new MccEntry(450,"kr",2)); //Korea (Republic of)
table.add(new MccEntry(452,"vn",2)); //Viet Nam (Socialist Republic of)
table.add(new MccEntry(454,"hk",2)); //"Hong Kong, China"
@@ -298,12 +321,12 @@ public final class MccTable
table.add(new MccEntry(470,"bd",2)); //Bangladesh (People's Republic of)
table.add(new MccEntry(472,"mv",2)); //Maldives (Republic of)
table.add(new MccEntry(502,"my",2)); //Malaysia
- table.add(new MccEntry(505,"au",2,"Australia/Sydney","en")); //Australia
+ table.add(new MccEntry(505,"au",2,"Australia/Sydney","en", 11)); //Australia
table.add(new MccEntry(510,"id",2)); //Indonesia (Republic of)
table.add(new MccEntry(514,"tl",2)); //Democratic Republic of Timor-Leste
table.add(new MccEntry(515,"ph",2)); //Philippines (Republic of the)
table.add(new MccEntry(520,"th",2)); //Thailand
- table.add(new MccEntry(525,"sg",2,"Singapore","en")); //Singapore (Republic of)
+ table.add(new MccEntry(525,"sg",2,"Singapore","en", 11)); //Singapore (Republic of)
table.add(new MccEntry(528,"bn",2)); //Brunei Darussalam
table.add(new MccEntry(530,"nz",2,"Pacific/Auckland", "en")); //New Zealand
table.add(new MccEntry(534,"mp",2)); //Northern Mariana Islands (Commonwealth of the)
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index f9015d9..fb45c7c 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -21,11 +21,13 @@ import android.app.AlarmManager;
import android.app.IActivityManager;
import android.content.Context;
import android.content.res.Configuration;
+import android.net.wifi.WifiManager;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Message;
import android.os.SystemProperties;
import android.os.Registrant;
+import android.provider.Settings;
import android.util.Log;
import java.util.ArrayList;
@@ -513,6 +515,29 @@ public final class SIMRecords extends IccRecords {
phone.setSystemLocale(language, country);
}
+ /**
+ * If the number of allowed wifi channels has not been set, set it based on
+ * the MCC of the SIM.
+ * @param mcc Mobile Country Code of the SIM
+ */
+ private void setWifiChannelsFromMccIfNeeded(int mcc) {
+ int wifiChannels = MccTable.wifiChannelsForMcc(mcc);
+
+ if (wifiChannels != 0) {
+ Context context = phone.getContext();
+ // only set to this default if the user hasn't manually set it
+ try {
+ Settings.Secure.getInt(context.getContentResolver(),
+ Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS);
+ } catch (Settings.SettingNotFoundException e) {
+ WifiManager wM = (WifiManager)
+ context.getSystemService(Context.WIFI_SERVICE);
+ // don't persist
+ wM.setNumAllowedChannels(wifiChannels, false);
+ }
+ }
+ }
+
//***** Overridden from Handler
public void handleMessage(Message msg) {
AsyncResult ar;
@@ -559,6 +584,7 @@ public final class SIMRecords extends IccRecords {
int mcc = Integer.parseInt(imsi.substring(0, 3));
setTimezoneFromMccIfNeeded(mcc);
setLocaleFromMccIfNeeded(mcc);
+ setWifiChannelsFromMccIfNeeded(mcc);
break;
case EVENT_GET_MBI_DONE:
diff --git a/test-runner/android/test/IsolatedContext.java b/test-runner/android/test/IsolatedContext.java
index 2866666..03d95b7 100644
--- a/test-runner/android/test/IsolatedContext.java
+++ b/test-runner/android/test/IsolatedContext.java
@@ -2,6 +2,8 @@ package android.test;
import com.google.android.collect.Lists;
+import android.accounts.AccountManager;
+import android.accounts.OnAccountsUpdatedListener;
import android.content.ContextWrapper;
import android.content.ContentResolver;
import android.content.Intent;
@@ -11,6 +13,8 @@ import android.content.BroadcastReceiver;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
import java.util.List;
@@ -21,6 +25,7 @@ import java.util.List;
public class IsolatedContext extends ContextWrapper {
private ContentResolver mResolver;
+ private final MockAccountManager mMockAccountManager;
private List<Intent> mBroadcastIntents = Lists.newArrayList();
@@ -28,6 +33,7 @@ public class IsolatedContext extends ContextWrapper {
ContentResolver resolver, Context targetContext) {
super(targetContext);
mResolver = resolver;
+ mMockAccountManager = new MockAccountManager();
}
/** Returns the list of intents that were broadcast since the last call to this method. */
@@ -78,8 +84,21 @@ public class IsolatedContext extends ContextWrapper {
@Override
public Object getSystemService(String name) {
- // No services exist in this context.
+ if (Context.ACCOUNT_SERVICE.equals(name)) {
+ return mMockAccountManager;
+ }
+ // No other services exist in this context.
return null;
}
+ private class MockAccountManager extends AccountManager {
+ public MockAccountManager() {
+ super(IsolatedContext.this, null /* IAccountManager */, null /* handler */);
+ }
+
+ public void addOnAccountsUpdatedListener(OnAccountsUpdatedListener listener,
+ Handler handler, boolean updateImmediately) {
+ // do nothing
+ }
+ }
}
diff --git a/test-runner/android/test/SyncBaseInstrumentation.java b/test-runner/android/test/SyncBaseInstrumentation.java
index 772d75c..bf9e783 100644
--- a/test-runner/android/test/SyncBaseInstrumentation.java
+++ b/test-runner/android/test/SyncBaseInstrumentation.java
@@ -22,6 +22,7 @@ import android.os.Bundle;
import android.os.RemoteException;
import android.os.SystemClock;
import android.net.Uri;
+import android.accounts.Account;
/**
* If you would like to test sync a single provider with an
@@ -47,7 +48,8 @@ public class SyncBaseInstrumentation extends InstrumentationTestCase {
protected void syncProvider(Uri uri, String account, String authority) throws Exception {
Bundle extras = new Bundle();
extras.putBoolean(ContentResolver.SYNC_EXTRAS_FORCE, true);
- extras.putString(ContentResolver.SYNC_EXTRAS_ACCOUNT, account);
+ Account account1 = new Account(account, "com.google.GAIA");
+ extras.putParcelable(ContentResolver.SYNC_EXTRAS_ACCOUNT, account1);
mContentResolver.startSync(uri, extras);
long startTimeInMillis = SystemClock.elapsedRealtime();
@@ -64,7 +66,7 @@ public class SyncBaseInstrumentation extends InstrumentationTestCase {
break;
}
- if (isSyncActive(account, authority)) {
+ if (isSyncActive(account1, authority)) {
counter = 0;
continue;
}
@@ -85,7 +87,7 @@ public class SyncBaseInstrumentation extends InstrumentationTestCase {
* entry is in either the Pending or Active tables.
* @return
*/
- private boolean isSyncActive(String account, String authority) {
+ private boolean isSyncActive(Account account, String authority) {
try {
return ContentResolver.getContentService().isSyncActive(account,
authority);
diff --git a/test-runner/android/test/mock/MockContentProvider.java b/test-runner/android/test/mock/MockContentProvider.java
index d04fc44..74f86d8 100644
--- a/test-runner/android/test/mock/MockContentProvider.java
+++ b/test-runner/android/test/mock/MockContentProvider.java
@@ -18,7 +18,11 @@ package android.test.mock;
import android.content.ContentValues;
import android.content.IContentProvider;
-import android.content.ISyncAdapter;
+import android.content.Entity;
+import android.content.EntityIterator;
+import android.content.ContentProviderResult;
+import android.content.ContentProviderOperation;
+import android.content.OperationApplicationException;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.CursorWindow;
@@ -30,6 +34,7 @@ import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import java.io.FileNotFoundException;
+import java.util.ArrayList;
/**
* Mock implementation of IContentProvider that does nothing. All methods are non-functional and
@@ -48,6 +53,10 @@ public class MockContentProvider implements IContentProvider {
return 0;
}
+ public Uri insertEntity(Uri uri, Entity entities) throws RemoteException {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
@SuppressWarnings("unused")
public IBulkCursor bulkQuery(Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder, IContentObserver observer,
@@ -62,11 +71,6 @@ public class MockContentProvider implements IContentProvider {
}
@SuppressWarnings("unused")
- public ISyncAdapter getSyncAdapter() throws RemoteException {
- throw new UnsupportedOperationException("unimplemented mock method");
- }
-
- @SuppressWarnings("unused")
public String getType(Uri url) throws RemoteException {
throw new UnsupportedOperationException("unimplemented mock method");
}
@@ -87,19 +91,33 @@ public class MockContentProvider implements IContentProvider {
throws FileNotFoundException {
throw new UnsupportedOperationException("unimplemented mock method");
}
-
+
+ public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
+ throws RemoteException, OperationApplicationException {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
@SuppressWarnings("unused")
public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs,
String sortOrder) throws RemoteException {
throw new UnsupportedOperationException("unimplemented mock method");
}
+ public EntityIterator queryEntities(Uri url, String selection, String[] selectionArgs,
+ String sortOrder) throws RemoteException {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
@SuppressWarnings("unused")
public int update(Uri url, ContentValues values, String selection, String[] selectionArgs)
throws RemoteException {
throw new UnsupportedOperationException("unimplemented mock method");
}
+ public int updateEntity(Uri uri, Entity entity) throws RemoteException {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
public IBinder asBinder() {
throw new UnsupportedOperationException("unimplemented mock method");
}
diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java
index 6ef5539..f98a251 100644
--- a/test-runner/android/test/mock/MockPackageManager.java
+++ b/test-runner/android/test/mock/MockPackageManager.java
@@ -297,9 +297,6 @@ public class MockPackageManager extends PackageManager {
throw new UnsupportedOperationException();
}
- /**
- * @hide - to match hiding in superclass
- */
@Override
public String getInstallerPackageName(String packageName) {
throw new UnsupportedOperationException();
diff --git a/tests/AndroidTests/run_test.sh b/tests/AndroidTests/run_test.sh
index 0cdf63f..6c3710a 100755
--- a/tests/AndroidTests/run_test.sh
+++ b/tests/AndroidTests/run_test.sh
@@ -1,4 +1,4 @@
framework=/system/framework
bpath=$framework/core.jar:$framework/ext.jar:$framework/framework.jar:$framework/android.test.runner.jar
-adb shell exec dalvikvm -Xbootclasspath:$bpath -cp system/app/AndroidTests.apk \
+adb shell exec dalvikvm -Xbootclasspath:$bpath -cp system/app/AndroidTests.apk:data/app/AndroidTests.apk \
com.android.internal.util.WithFramework junit.textui.TestRunner $*
diff --git a/tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java b/tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java
new file mode 100644
index 0000000..6b8e1f0
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java
@@ -0,0 +1,181 @@
+/*
+ * 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.unit_tests.accounts;
+
+import android.test.AndroidTestCase;
+import android.test.RenamingDelegatingContext;
+import android.test.IsolatedContext;
+import android.test.mock.MockContext;
+import android.test.mock.MockContentResolver;
+import android.content.*;
+import android.accounts.Account;
+import android.accounts.AccountManagerService;
+import android.os.Bundle;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Map;
+
+public class AccountManagerServiceTest extends AndroidTestCase {
+ @Override
+ protected void setUp() throws Exception {
+ final String filenamePrefix = "test.";
+ MockContentResolver resolver = new MockContentResolver();
+ RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext(
+ new MockContext(), // The context that most methods are delegated to
+ getContext(), // The context that file methods are delegated to
+ filenamePrefix);
+ Context context = new IsolatedContext(resolver, targetContextWrapper);
+ setContext(context);
+ }
+
+ public class AccountSorter implements Comparator<Account> {
+ public int compare(Account object1, Account object2) {
+ if (object1 == object2) return 0;
+ if (object1 == null) return 1;
+ if (object2 == null) return -1;
+ int result = object1.mType.compareTo(object2.mType);
+ if (result != 0) return result;
+ return object1.mName.compareTo(object2.mName);
+ }
+ }
+
+ public void testCheckAddAccount() throws Exception {
+ AccountManagerService ams = new AccountManagerService(getContext());
+ Account a11 = new Account("account1", "type1");
+ Account a21 = new Account("account2", "type1");
+ Account a31 = new Account("account3", "type1");
+ Account a12 = new Account("account1", "type2");
+ Account a22 = new Account("account2", "type2");
+ Account a32 = new Account("account3", "type2");
+ assertTrue(ams.addAccount(a11, "p11", null));
+ assertTrue(ams.addAccount(a12, "p12", null));
+ assertTrue(ams.addAccount(a21, "p21", null));
+ assertTrue(ams.addAccount(a22, "p22", null));
+ assertTrue(ams.addAccount(a31, "p31", null));
+ assertTrue(ams.addAccount(a32, "p32", null));
+
+ assertFalse("duplicate account insertion should fail", ams.addAccount(a32, "p", null));
+
+ Account[] accounts = ams.getAccounts();
+ Arrays.sort(accounts, new AccountSorter());
+ assertEquals(6, accounts.length);
+ assertEquals(a11, accounts[0]);
+ assertEquals(a21, accounts[1]);
+ assertEquals(a31, accounts[2]);
+ assertEquals(a12, accounts[3]);
+ assertEquals(a22, accounts[4]);
+ assertEquals(a32, accounts[5]);
+
+ accounts = ams.getAccountsByType("type1" );
+ Arrays.sort(accounts, new AccountSorter());
+ assertEquals(3, accounts.length);
+ assertEquals(a11, accounts[0]);
+ assertEquals(a21, accounts[1]);
+ assertEquals(a31, accounts[2]);
+
+ ams.removeAccount(a21);
+
+ accounts = ams.getAccountsByType("type1" );
+ Arrays.sort(accounts, new AccountSorter());
+ assertEquals(2, accounts.length);
+ assertEquals(a11, accounts[0]);
+ assertEquals(a31, accounts[1]);
+ }
+
+ public void testPasswords() throws Exception {
+ AccountManagerService ams = new AccountManagerService(getContext());
+ Account a11 = new Account("account1", "type1");
+ Account a12 = new Account("account1", "type2");
+ assertTrue(ams.addAccount(a11, "p11", null));
+ assertTrue(ams.addAccount(a12, "p12", null));
+
+ assertEquals("p11", ams.getPassword(a11));
+ assertEquals("p12", ams.getPassword(a12));
+
+ ams.setPassword(a11, "p11b");
+
+ assertEquals("p11b", ams.getPassword(a11));
+ assertEquals("p12", ams.getPassword(a12));
+ }
+
+ public void testUserdata() throws Exception {
+ AccountManagerService ams = new AccountManagerService(getContext());
+ Account a11 = new Account("account1", "type1");
+ Bundle u11 = new Bundle();
+ u11.putString("a", "a_a11");
+ u11.putString("b", "b_a11");
+ u11.putString("c", "c_a11");
+ Account a12 = new Account("account1", "type2");
+ Bundle u12 = new Bundle();
+ u12.putString("a", "a_a12");
+ u12.putString("b", "b_a12");
+ u12.putString("c", "c_a12");
+ assertTrue(ams.addAccount(a11, "p11", u11));
+ assertTrue(ams.addAccount(a12, "p12", u12));
+
+ assertEquals("a_a11", ams.getUserData(a11, "a"));
+ assertEquals("b_a11", ams.getUserData(a11, "b"));
+ assertEquals("c_a11", ams.getUserData(a11, "c"));
+ assertEquals("a_a12", ams.getUserData(a12, "a"));
+ assertEquals("b_a12", ams.getUserData(a12, "b"));
+ assertEquals("c_a12", ams.getUserData(a12, "c"));
+
+ ams.setUserData(a11, "b", "b_a11b");
+
+ assertEquals("a_a11", ams.getUserData(a11, "a"));
+ assertEquals("b_a11b", ams.getUserData(a11, "b"));
+ assertEquals("c_a11", ams.getUserData(a11, "c"));
+ assertEquals("a_a12", ams.getUserData(a12, "a"));
+ assertEquals("b_a12", ams.getUserData(a12, "b"));
+ assertEquals("c_a12", ams.getUserData(a12, "c"));
+ }
+
+ public void testAuthtokens() throws Exception {
+ AccountManagerService ams = new AccountManagerService(getContext());
+ Account a11 = new Account("account1", "type1");
+ Account a12 = new Account("account1", "type2");
+ assertTrue(ams.addAccount(a11, "p11", null));
+ assertTrue(ams.addAccount(a12, "p12", null));
+
+ ams.setAuthToken(a11, "att1", "a11_att1");
+ ams.setAuthToken(a11, "att2", "a11_att2");
+ ams.setAuthToken(a11, "att3", "a11_att3");
+ ams.setAuthToken(a12, "att1", "a12_att1");
+ ams.setAuthToken(a12, "att2", "a12_att2");
+ ams.setAuthToken(a12, "att3", "a12_att3");
+
+ assertEquals("a11_att1", ams.peekAuthToken(a11, "att1"));
+ assertEquals("a11_att2", ams.peekAuthToken(a11, "att2"));
+ assertEquals("a11_att3", ams.peekAuthToken(a11, "att3"));
+ assertEquals("a12_att1", ams.peekAuthToken(a12, "att1"));
+ assertEquals("a12_att2", ams.peekAuthToken(a12, "att2"));
+ assertEquals("a12_att3", ams.peekAuthToken(a12, "att3"));
+
+ ams.setAuthToken(a11, "att3", "a11_att3b");
+ ams.invalidateAuthToken(a12.mType, "a12_att2");
+
+ assertEquals("a11_att1", ams.peekAuthToken(a11, "att1"));
+ assertEquals("a11_att2", ams.peekAuthToken(a11, "att2"));
+ assertEquals("a11_att3b", ams.peekAuthToken(a11, "att3"));
+ assertEquals("a12_att1", ams.peekAuthToken(a12, "att1"));
+ assertNull(ams.peekAuthToken(a12, "att2"));
+ assertEquals("a12_att3", ams.peekAuthToken(a12, "att3"));
+
+ assertNull(ams.readAuthTokenFromDatabase(a12, "att2"));
+ }
+} \ No newline at end of file
diff --git a/tests/CoreTests/android/content/SyncStorageEngineTest.java b/tests/CoreTests/android/content/SyncStorageEngineTest.java
index dee6e38..533338e 100644
--- a/tests/CoreTests/android/content/SyncStorageEngineTest.java
+++ b/tests/CoreTests/android/content/SyncStorageEngineTest.java
@@ -20,6 +20,7 @@ import android.test.AndroidTestCase;
import android.test.RenamingDelegatingContext;
import android.test.mock.MockContext;
import android.test.mock.MockContentResolver;
+import android.accounts.Account;
public class SyncStorageEngineTest extends AndroidTestCase {
@@ -28,7 +29,7 @@ public class SyncStorageEngineTest extends AndroidTestCase {
* correcponding sync is finished. This can happen if the clock changes while we are syncing.
*/
public void testPurgeActiveSync() throws Exception {
- final String account = "a@example.com";
+ final Account account = new Account("a@example.com", "example.type");
final String authority = "testprovider";
MockContentResolver mockResolver = new MockContentResolver();
diff --git a/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java b/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
index e8bd239..ae11ed1 100644
--- a/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -302,6 +302,11 @@ public class PhoneNumberUtilsTest extends TestCase {
number.append("800-55512");
PhoneNumberUtils.formatNanpNumber(number);
assertEquals("800-555-12", number.toString());
+
+ number.clear();
+ number.append("46645");
+ PhoneNumberUtils.formatNanpNumber(number);
+ assertEquals("46645", number.toString());
}
@SmallTest
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index 4f162b3..95a7ae3 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -83,7 +83,12 @@ public class FileFilter {
};
static final String [] ignoreTestList = {
- };
+ // RegExp is exponatal
+ "fast/regex/test1.html",
+ "fast/regex/slow.html",
+ // RegExp is too large, causing OOM
+ "fast/js/regexp-charclass-crash.html"
+ };
static void fillIgnoreResultSet() {
// need test plugin
@@ -195,11 +200,7 @@ public class FileFilter {
ignoreResultList.add("fast/loader/local-iFrame-source-from-local.html");
// extra spacing because iFrames rendered next to each other on Apple
ignoreResultList.add("fast/loader/opaque-base-url.html");
- // RegExp is too large, causing OOM
- ignoreResultList.add("fast/js/regexp-charclass-crash.html");
ignoreResultList.add("fast/text/plain-text-line-breaks.html");
-
-
}
static void fillBugTable() {
diff --git a/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java b/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
index aa3d186..42c1e78 100644
--- a/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
+++ b/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
@@ -8,6 +8,7 @@ import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.test.AndroidTestCase;
import android.text.TextUtils;
+import android.accounts.Account;
import java.util.ArrayList;
import java.util.Map;
@@ -26,7 +27,7 @@ public class AbstractTableMergerTest extends AndroidTestCase {
static final Uri TABLE_URI = Uri.withAppendedPath(CONTENT_URI, TABLE_NAME);
static final Uri DELETED_TABLE_URI = Uri.withAppendedPath(CONTENT_URI, DELETED_TABLE_NAME);
- private final String ACCOUNT = "account@goo.com";
+ private final Account ACCOUNT = new Account("account@goo.com", "example.type");
private final ArrayList<Expectation> mExpectations = Lists.newArrayList();
@@ -65,25 +66,31 @@ public class AbstractTableMergerTest extends AndroidTestCase {
mExpectations.clear();
}
- ContentValues newValues(String data, String syncId, String syncAccount,
+ ContentValues newValues(String data, String syncId, Account syncAccount,
String syncTime, String syncVersion, Long syncLocalId) {
ContentValues values = new ContentValues();
if (data != null) values.put("data", data);
if (syncTime != null) values.put("_sync_time", syncTime);
if (syncVersion != null) values.put("_sync_version", syncVersion);
if (syncId != null) values.put("_sync_id", syncId);
- if (syncAccount != null) values.put("_sync_account", syncAccount);
+ if (syncAccount != null) {
+ values.put("_sync_account", syncAccount.mName);
+ values.put("_sync_account_type", syncAccount.mType);
+ }
values.put("_sync_local_id", syncLocalId);
values.put("_sync_dirty", 0);
return values;
}
- ContentValues newDeletedValues(String syncId, String syncAccount, String syncVersion,
+ ContentValues newDeletedValues(String syncId, Account syncAccount, String syncVersion,
Long syncLocalId) {
ContentValues values = new ContentValues();
if (syncVersion != null) values.put("_sync_version", syncVersion);
if (syncId != null) values.put("_sync_id", syncId);
- if (syncAccount != null) values.put("_sync_account", syncAccount);
+ if (syncAccount != null) {
+ values.put("_sync_account", syncAccount.mName);
+ values.put("_sync_account_type", syncAccount.mType);
+ }
if (syncLocalId != null) values.put("_sync_local_id", syncLocalId);
return values;
}
@@ -380,6 +387,7 @@ public class AbstractTableMergerTest extends AndroidTestCase {
+ "_sync_local_id INTEGER, "
+ "_sync_dirty INTEGER NOT NULL DEFAULT 0, "
+ "_sync_account TEXT, "
+ + "_sync_account_type TEXT, "
+ "_sync_mark INTEGER)");
mDb.execSQL("CREATE TABLE deleted_items ("
@@ -388,6 +396,7 @@ public class AbstractTableMergerTest extends AndroidTestCase {
+ "_sync_id TEXT, "
+ "_sync_local_id INTEGER, "
+ "_sync_account TEXT, "
+ + "_sync_account_type TEXT, "
+ "_sync_mark INTEGER)");
}
@@ -501,7 +510,7 @@ public class AbstractTableMergerTest extends AndroidTestCase {
throw new UnsupportedOperationException();
}
- public void onSyncStart(SyncContext context, String account) {
+ public void onSyncStart(SyncContext context, Account account) {
throw new UnsupportedOperationException();
}
@@ -509,7 +518,7 @@ public class AbstractTableMergerTest extends AndroidTestCase {
throw new UnsupportedOperationException();
}
- public String getSyncingAccount() {
+ public Account getSyncingAccount() {
throw new UnsupportedOperationException();
}
@@ -544,24 +553,24 @@ public class AbstractTableMergerTest extends AndroidTestCase {
throw new UnsupportedOperationException();
}
- protected void onAccountsChanged(String[] accountsArray) {
+ protected void onAccountsChanged(Account[] accountsArray) {
throw new UnsupportedOperationException();
}
- protected void deleteRowsForRemovedAccounts(Map<String, Boolean> accounts, String table,
- String accountColumnName) {
+ protected void deleteRowsForRemovedAccounts(Map<Account, Boolean> accounts, String table
+ ) {
throw new UnsupportedOperationException();
}
- public void wipeAccount(String account) {
+ public void wipeAccount(Account account) {
throw new UnsupportedOperationException();
}
- public byte[] readSyncDataBytes(String account) {
+ public byte[] readSyncDataBytes(Account account) {
throw new UnsupportedOperationException();
}
- public void writeSyncDataBytes(String account, byte[] data) {
+ public void writeSyncDataBytes(Account account, byte[] data) {
throw new UnsupportedOperationException();
}
}
diff --git a/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java b/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
new file mode 100644
index 0000000..e9a43d7
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
@@ -0,0 +1,468 @@
+/*
+ * 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.content;
+
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
+import junit.framework.TestCase;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+@SmallTest
+public class ContentProviderOperationTest extends TestCase {
+ private final static Uri sTestUri1 = Uri.parse("content://authority/blah");
+ private final static ContentValues sTestValues1;
+
+ private final static Class<ContentProviderOperation.Builder> CLASS_BUILDER =
+ ContentProviderOperation.Builder.class;
+ private final static Class<ContentProviderOperation> CLASS_OPERATION =
+ ContentProviderOperation.class;
+
+ static {
+ sTestValues1 = new ContentValues();
+ sTestValues1.put("a", 1);
+ sTestValues1.put("b", "two");
+ }
+
+ public void testInsert() throws OperationApplicationException {
+ ContentProviderOperation op1 = ContentProviderOperation.newInsert(sTestUri1)
+ .withValues(sTestValues1)
+ .build();
+ ContentProviderResult result = op1.apply(new TestContentProvider() {
+ public Uri insert(Uri uri, ContentValues values) {
+ assertEquals(sTestUri1.toString(), uri.toString());
+ assertEquals(sTestValues1.toString(), values.toString());
+ return uri.buildUpon().appendPath("19").build();
+ }
+ }, null, 0);
+ assertEquals(sTestUri1.buildUpon().appendPath("19").toString(), result.uri.toString());
+ }
+
+ public void testInsertNoValues() throws OperationApplicationException {
+ ContentProviderOperation op1 = ContentProviderOperation.newInsert(sTestUri1)
+ .build();
+ ContentProviderResult result = op1.apply(new TestContentProvider() {
+ public Uri insert(Uri uri, ContentValues values) {
+ assertEquals(sTestUri1.toString(), uri.toString());
+ assertNull(values);
+ return uri.buildUpon().appendPath("19").build();
+ }
+ }, null, 0);
+ assertEquals(sTestUri1.buildUpon().appendPath("19").toString(), result.uri.toString());
+ }
+
+ public void testInsertFailed() {
+ ContentProviderOperation op1 = ContentProviderOperation.newInsert(sTestUri1)
+ .withValues(sTestValues1)
+ .build();
+ try {
+ op1.apply(new TestContentProvider() {
+ public Uri insert(Uri uri, ContentValues values) {
+ assertEquals(sTestUri1.toString(), uri.toString());
+ assertEquals(sTestValues1.toString(), values.toString());
+ return null;
+ }
+ }, null, 0);
+ fail("the apply should have thrown an OperationApplicationException");
+ } catch (OperationApplicationException e) {
+ // this is the expected case
+ }
+ }
+
+ public void testInsertWithBackRefs() throws OperationApplicationException {
+ ContentProviderResult[] previousResults = new ContentProviderResult[4];
+ previousResults[0] = new ContentProviderResult(100);
+ previousResults[1] = new ContentProviderResult(101);
+ previousResults[2] = new ContentProviderResult(102);
+ previousResults[3] = new ContentProviderResult(103);
+ ContentProviderOperation op1 = ContentProviderOperation.newInsert(sTestUri1)
+ .withValues(sTestValues1)
+ .withValueBackReference("a1", 3)
+ .withValueBackReference("a2", 1)
+ .build();
+ ContentProviderResult result = op1.apply(new TestContentProvider() {
+ public Uri insert(Uri uri, ContentValues values) {
+ assertEquals(sTestUri1.toString(), uri.toString());
+ ContentValues expected = new ContentValues(sTestValues1);
+ expected.put("a1", 103);
+ expected.put("a2", 101);
+ assertEquals(expected.toString(), values.toString());
+ return uri.buildUpon().appendPath("19").build();
+ }
+ }, previousResults, previousResults.length);
+ assertEquals(sTestUri1.buildUpon().appendPath("19").toString(), result.uri.toString());
+ }
+
+ public void testUpdate() throws OperationApplicationException {
+ ContentProviderOperation op1 = ContentProviderOperation.newInsert(sTestUri1)
+ .withValues(sTestValues1)
+ .build();
+ ContentProviderResult[] backRefs = new ContentProviderResult[2];
+ ContentProviderResult result = op1.apply(new TestContentProvider() {
+ public Uri insert(Uri uri, ContentValues values) {
+ assertEquals(sTestUri1.toString(), uri.toString());
+ assertEquals(sTestValues1.toString(), values.toString());
+ return uri.buildUpon().appendPath("19").build();
+ }
+ }, backRefs, 1);
+ assertEquals(sTestUri1.buildUpon().appendPath("19").toString(), result.uri.toString());
+ }
+
+ public void testValueBackRefs() {
+ ContentValues values = new ContentValues();
+ values.put("a", "in1");
+ values.put("a2", "in2");
+ values.put("b", "in3");
+ values.put("c", "in4");
+
+ ContentProviderResult[] previousResults = new ContentProviderResult[4];
+ previousResults[0] = new ContentProviderResult(100);
+ previousResults[1] = new ContentProviderResult(101);
+ previousResults[2] = new ContentProviderResult(102);
+ previousResults[3] = new ContentProviderResult(103);
+
+ ContentValues expectedValues = new ContentValues(values);
+ expectedValues.put("a1", "103");
+ expectedValues.put("a2", "101");
+ expectedValues.put("a3", "102");
+
+ ContentProviderOperation op1 = ContentProviderOperation.newInsert(sTestUri1)
+ .withValues(values)
+ .withValueBackReference("a1", 3)
+ .withValueBackReference("a2", 1)
+ .withValueBackReference("a3", 2)
+ .build();
+ ContentValues v2 = op1.resolveValueBackReferences(previousResults, previousResults.length);
+ assertEquals(expectedValues, v2);
+ }
+
+ public void testSelectionBackRefs() {
+ ContentProviderResult[] previousResults = new ContentProviderResult[4];
+ previousResults[0] = new ContentProviderResult(100);
+ previousResults[1] = new ContentProviderResult(101);
+ previousResults[2] = new ContentProviderResult(102);
+ previousResults[3] = new ContentProviderResult(103);
+
+ String[] selectionArgs = new String[]{"a", null, null, "b", null};
+
+ ContentProviderOperation op1 = ContentProviderOperation.newUpdate(sTestUri1)
+ .withSelectionBackReference(1, 3)
+ .withSelectionBackReference(2, 1)
+ .withSelectionBackReference(4, 2)
+ .withSelection("unused", selectionArgs)
+ .build();
+ String[] s2 = op1.resolveSelectionArgsBackReferences(
+ previousResults, previousResults.length);
+ assertEquals("a,103,101,b,102", TextUtils.join(",", s2));
+ }
+
+ public void testParcelingOperation() throws NoSuchFieldException, IllegalAccessException,
+ NoSuchMethodException, InvocationTargetException, InstantiationException {
+ Parcel parcel = Parcel.obtain();
+ ContentProviderOperation op1;
+ ContentProviderOperation op2;
+
+ HashMap<Integer, Integer> selArgsBackRef = new HashMap<Integer, Integer>();
+ selArgsBackRef.put(1, 2);
+ selArgsBackRef.put(3, 4);
+
+ ContentValues values = new ContentValues();
+ values.put("v1", "val1");
+ values.put("v2", "43");
+
+ ContentValues valuesBackRef = new ContentValues();
+ values.put("v3", "val3");
+ values.put("v4", "44");
+
+ try {
+ ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(
+ Uri.parse("content://goo/bar"));
+
+ builderSetExpectedCount(builder, 42);
+ builderSetSelection(builder, "selection");
+ builderSetSelectionArgs(builder, new String[]{"a", "b"});
+ builderSetSelectionArgsBackReferences(builder, selArgsBackRef);
+ builderSetValues(builder, values);
+ builderSetValuesBackReferences(builder, valuesBackRef);
+
+ op1 = newOperationFromBuilder(builder);
+ op1.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ op2 = ContentProviderOperation.CREATOR.createFromParcel(parcel);
+
+ assertEquals(1 /* ContentProviderOperation.TYPE_INSERT */, operationGetType(op2));
+ assertEquals("content://goo/bar", operationGetUri(op2).toString());
+ assertEquals(Integer.valueOf(42), operationGetExpectedCount(op2));
+ assertEquals("selection", operationGetSelection(op2));
+ assertEquals(2, operationGetSelectionArgs(op2).length);
+ assertEquals("a", operationGetSelectionArgs(op2)[0]);
+ assertEquals("b", operationGetSelectionArgs(op2)[1]);
+ assertEquals(values, operationGetValues(op2));
+ assertEquals(valuesBackRef, operationGetValuesBackReferences(op2));
+ assertEquals(2, operationGetSelectionArgsBackReferences(op2).size());
+ assertEquals(Integer.valueOf(2), operationGetSelectionArgsBackReferences(op2).get(1));
+ assertEquals(Integer.valueOf(4), operationGetSelectionArgsBackReferences(op2).get(3));
+ } finally {
+ parcel.recycle();
+ }
+
+ try {
+ ContentProviderOperation.Builder builder = ContentProviderOperation.newUpdate(
+ Uri.parse("content://goo/bar"));
+
+ builderSetSelectionArgsBackReferences(builder, selArgsBackRef);
+
+ op1 = newOperationFromBuilder(builder);
+ op1.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ op2 = ContentProviderOperation.CREATOR.createFromParcel(parcel);
+ assertEquals(2 /* ContentProviderOperation.TYPE_UPDATE */, operationGetType(op2));
+ assertEquals("content://goo/bar", operationGetUri(op2).toString());
+ assertNull(operationGetEntity(op2));
+ assertNull(operationGetExpectedCount(op2));
+ assertNull(operationGetSelection(op2));
+ assertNull(operationGetSelectionArgs(op2));
+ assertNull(operationGetValues(op2));
+ assertNull(operationGetValuesBackReferences(op2));
+ assertEquals(2, operationGetSelectionArgsBackReferences(op2).size());
+ assertEquals(Integer.valueOf(2), operationGetSelectionArgsBackReferences(op2).get(1));
+ assertEquals(Integer.valueOf(4), operationGetSelectionArgsBackReferences(op2).get(3));
+ } finally {
+ parcel.recycle();
+ }
+
+ try {
+ ContentProviderOperation.Builder builder = ContentProviderOperation.newDelete(
+ Uri.parse("content://goo/bar"));
+
+ op1 = newOperationFromBuilder(builder);
+ op1.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ op2 = ContentProviderOperation.CREATOR.createFromParcel(parcel);
+ assertEquals(3 /* ContentProviderOperation.TYPE_DELETE */, operationGetType(op2));
+ assertEquals("content://goo/bar", operationGetUri(op2).toString());
+ assertNull(operationGetEntity(op2));
+ assertNull(operationGetExpectedCount(op2));
+ assertNull(operationGetSelection(op2));
+ assertNull(operationGetSelectionArgs(op2));
+ assertNull(operationGetValues(op2));
+ assertNull(operationGetValuesBackReferences(op2));
+ assertNull(operationGetSelectionArgsBackReferences(op2));
+ } finally {
+ parcel.recycle();
+ }
+ }
+
+ private static ContentProviderOperation newOperationFromBuilder(
+ ContentProviderOperation.Builder builder)
+ throws NoSuchMethodException, InstantiationException, IllegalAccessException,
+ InvocationTargetException {
+ final Constructor constructor = CLASS_OPERATION.getDeclaredConstructor(CLASS_BUILDER);
+ constructor.setAccessible(true);
+ return (ContentProviderOperation) constructor.newInstance(builder);
+ }
+
+ private void builderSetSelectionArgsBackReferences(
+ ContentProviderOperation.Builder builder, HashMap<Integer, Integer> selArgsBackRef)
+ throws NoSuchFieldException, IllegalAccessException {
+ Field field;
+ field = CLASS_BUILDER.getDeclaredField("mSelectionArgsBackReferences");
+ field.setAccessible(true);
+ field.set(builder, selArgsBackRef);
+ }
+
+ private void builderSetValuesBackReferences(
+ ContentProviderOperation.Builder builder, ContentValues valuesBackReferences)
+ throws NoSuchFieldException, IllegalAccessException {
+ Field field;
+ field = CLASS_BUILDER.getDeclaredField("mValuesBackReferences");
+ field.setAccessible(true);
+ field.set(builder, valuesBackReferences);
+ }
+
+ private void builderSetSelection(
+ ContentProviderOperation.Builder builder, String selection)
+ throws NoSuchFieldException, IllegalAccessException {
+ Field field;
+ field = CLASS_BUILDER.getDeclaredField("mSelection");
+ field.setAccessible(true);
+ field.set(builder, selection);
+ }
+
+ private void builderSetSelectionArgs(
+ ContentProviderOperation.Builder builder, String[] selArgs)
+ throws NoSuchFieldException, IllegalAccessException {
+ Field field;
+ field = CLASS_BUILDER.getDeclaredField("mSelectionArgs");
+ field.setAccessible(true);
+ field.set(builder, selArgs);
+ }
+
+ private void builderSetValues(
+ ContentProviderOperation.Builder builder, ContentValues values)
+ throws NoSuchFieldException, IllegalAccessException {
+ Field field;
+ field = CLASS_BUILDER.getDeclaredField("mValues");
+ field.setAccessible(true);
+ field.set(builder, values);
+ }
+
+ private void builderSetEntity(
+ ContentProviderOperation.Builder builder, Entity entity)
+ throws NoSuchFieldException, IllegalAccessException {
+ Field field;
+ field = CLASS_BUILDER.getDeclaredField("mEntity");
+ field.setAccessible(true);
+ field.set(builder, entity);
+ }
+
+ private void builderSetExpectedCount(
+ ContentProviderOperation.Builder builder, Integer expectedCount)
+ throws NoSuchFieldException, IllegalAccessException {
+ Field field;
+ field = CLASS_BUILDER.getDeclaredField("mExpectedCount");
+ field.setAccessible(true);
+ field.set(builder, expectedCount);
+ }
+
+ private int operationGetType(ContentProviderOperation operation)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = CLASS_OPERATION.getDeclaredField("mType");
+ field.setAccessible(true);
+ return field.getInt(operation);
+ }
+
+ private Uri operationGetUri(ContentProviderOperation operation)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = CLASS_OPERATION.getDeclaredField("mUri");
+ field.setAccessible(true);
+ return (Uri) field.get(operation);
+ }
+
+ private String operationGetSelection(ContentProviderOperation operation)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = CLASS_OPERATION.getDeclaredField("mSelection");
+ field.setAccessible(true);
+ return (String) field.get(operation);
+ }
+
+ private String[] operationGetSelectionArgs(ContentProviderOperation operation)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = CLASS_OPERATION.getDeclaredField("mSelectionArgs");
+ field.setAccessible(true);
+ return (String[]) field.get(operation);
+ }
+
+ private ContentValues operationGetValues(ContentProviderOperation operation)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = CLASS_OPERATION.getDeclaredField("mValues");
+ field.setAccessible(true);
+ return (ContentValues) field.get(operation);
+ }
+
+ private Entity operationGetEntity(ContentProviderOperation operation)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = CLASS_OPERATION.getDeclaredField("mEntity");
+ field.setAccessible(true);
+ return (Entity) field.get(operation);
+ }
+
+ private Integer operationGetExpectedCount(ContentProviderOperation operation)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = CLASS_OPERATION.getDeclaredField("mExpectedCount");
+ field.setAccessible(true);
+ return (Integer) field.get(operation);
+ }
+
+ private ContentValues operationGetValuesBackReferences(ContentProviderOperation operation)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = CLASS_OPERATION.getDeclaredField("mValuesBackReferences");
+ field.setAccessible(true);
+ return (ContentValues) field.get(operation);
+ }
+
+ private Map<Integer, Integer> operationGetSelectionArgsBackReferences(
+ ContentProviderOperation operation)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = CLASS_OPERATION.getDeclaredField("mSelectionArgsBackReferences");
+ field.setAccessible(true);
+ return (Map<Integer, Integer>) field.get(operation);
+ }
+
+ public void testParcelingResult() {
+ Parcel parcel = Parcel.obtain();
+ ContentProviderResult result1;
+ ContentProviderResult result2;
+ try {
+ result1 = new ContentProviderResult(Uri.parse("content://goo/bar"));
+ result1.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ result2 = ContentProviderResult.CREATOR.createFromParcel(parcel);
+ assertEquals("content://goo/bar", result2.uri.toString());
+ assertNull(result2.count);
+ } finally {
+ parcel.recycle();
+ }
+
+ parcel = Parcel.obtain();
+ try {
+ result1 = new ContentProviderResult(42);
+ result1.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ result2 = ContentProviderResult.CREATOR.createFromParcel(parcel);
+ assertEquals(Integer.valueOf(42), result2.count);
+ assertNull(result2.uri);
+ } finally {
+ parcel.recycle();
+ }
+ }
+
+ static class TestContentProvider extends ContentProvider {
+ public boolean onCreate() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getType(Uri uri) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Uri insert(Uri uri, ContentValues values) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+ }
+} \ No newline at end of file
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 01c8140..3f37069 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -15,7 +15,7 @@
#include <utils/String8.h>
#include <utils/Vector.h>
#include <utils/RefBase.h>
-#include <utils/ZipFile.h>
+#include "ZipFile.h"
#include "Bundle.h"
#include "SourcePos.h"
@@ -125,7 +125,9 @@ public:
{
//printf("new AaptFile created %s\n", (const char*)sourceFile);
}
- virtual ~AaptFile() { }
+ virtual ~AaptFile() {
+ free(mData);
+ }
const String8& getPath() const { return mPath; }
const AaptGroupEntry& getGroupEntry() const { return mGroupEntry; }
@@ -441,7 +443,13 @@ private:
AaptSymbolEntry mDefSymbol;
};
-class ResourceTypeSet;
+class ResourceTypeSet : public RefBase,
+ public KeyedVector<String8,sp<AaptGroup> >
+{
+public:
+ ResourceTypeSet();
+};
+
/**
* Asset hierarchy being operated on.
@@ -449,8 +457,8 @@ class ResourceTypeSet;
class AaptAssets : public AaptDir
{
public:
- AaptAssets() : AaptDir(String8(), String8()), mHaveIncludedAssets(false) { }
- virtual ~AaptAssets() { }
+ AaptAssets() : AaptDir(String8(), String8()), mHaveIncludedAssets(false), mRes(NULL) { }
+ virtual ~AaptAssets() { delete mRes; }
const String8& getPackage() const { return mPackage; }
void setPackage(const String8& package) { mPackage = package; mSymbolsPrivatePackage = package; }
@@ -498,7 +506,7 @@ public:
inline KeyedVector<String8, sp<ResourceTypeSet> >* getResources() { return mRes; }
inline void
- setResources(KeyedVector<String8, sp<ResourceTypeSet> >* res) { mRes = res; }
+ setResources(KeyedVector<String8, sp<ResourceTypeSet> >* res) { delete mRes; mRes = res; }
private:
String8 mPackage;
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index fdc859c..2d8973d 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -17,7 +17,10 @@ LOCAL_SRC_FILES := \
ResourceTable.cpp \
Images.cpp \
Resource.cpp \
- SourcePos.cpp
+ SourcePos.cpp \
+ ZipEntry.cpp \
+ ZipFile.cpp
+
LOCAL_CFLAGS += -Wno-format-y2k
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 2eb7a1d..9e712b8 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -7,7 +7,10 @@
#define __BUNDLE_H
#include <stdlib.h>
-#include <utils.h> // android
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <utils/String8.h>
#include <utils/Vector.h>
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index dc91a48..0e889f5 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -8,8 +8,10 @@
#include "ResourceTable.h"
#include "XMLNode.h"
-#include <utils.h>
-#include <utils/ZipFile.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <fcntl.h>
#include <errno.h>
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index 0a4c68b..f2414dd 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -44,6 +44,9 @@ struct image_info
}
free(allocRows);
}
+ free(info9Patch.xDivs);
+ free(info9Patch.yDivs);
+ free(info9Patch.colors);
}
png_uint_32 width;
@@ -833,6 +836,7 @@ static void write_png(const char* imageName,
int i;
png_unknown_chunk unknowns[1];
+ unknowns[0].data = NULL;
png_bytepp outRows = (png_bytepp) malloc((int) imageInfo.height * png_sizeof(png_bytep));
if (outRows == (png_bytepp) 0) {
@@ -939,6 +943,7 @@ static void write_png(const char* imageName,
free(outRows[i]);
}
free(outRows);
+ free(unknowns[0].data);
png_get_IHDR(write_ptr, write_info, &width, &height,
&bit_depth, &color_type, &interlace_type,
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 8bf2b07..a33b4d7 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -6,8 +6,10 @@
#include "Main.h"
#include "Bundle.h"
-#include <utils.h>
-#include <utils/ZipFile.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <stdlib.h>
#include <getopt.h>
diff --git a/tools/aapt/Main.h b/tools/aapt/Main.h
index 65c0a8a..34ca5e5 100644
--- a/tools/aapt/Main.h
+++ b/tools/aapt/Main.h
@@ -6,10 +6,13 @@
#ifndef __MAIN_H
#define __MAIN_H
-#include <utils.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include "Bundle.h"
#include "AaptAssets.h"
-#include <utils/ZipFile.h>
+#include "ZipFile.h"
extern int doVersion(Bundle* bundle);
extern int doList(Bundle* bundle);
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index eb7d6f5..8424169 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -7,8 +7,10 @@
#include "AaptAssets.h"
#include "ResourceTable.h"
-#include <utils.h>
-#include <utils/ZipFile.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <sys/types.h>
#include <dirent.h>
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 49ccf71..76b9d0a 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -45,13 +45,6 @@ static String8 parseResourceName(const String8& leaf)
}
}
-class ResourceTypeSet : public RefBase,
- public KeyedVector<String8,sp<AaptGroup> >
-{
-public:
- ResourceTypeSet();
-};
-
ResourceTypeSet::ResourceTypeSet()
:RefBase(),
KeyedVector<String8,sp<AaptGroup> >()
@@ -1115,6 +1108,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
printf(" Writing public definitions to %s.\n", bundle->getPublicOutputFile());
}
table.writePublicDefinitions(String16(assets->getPackage()), fp);
+ fclose(fp);
}
NOISY(
@@ -1132,7 +1126,6 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
return err;
}
}
-
return err;
}
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index 2a85bc7..832ba6c 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -486,6 +486,7 @@ XMLNode::XMLNode(const String8& filename, const String16& s1, const String16& s2
XMLNode::XMLNode(const String8& filename)
: mFilename(filename)
{
+ memset(&mCharsValue, 0, sizeof(mCharsValue));
}
XMLNode::type XMLNode::getType() const
diff --git a/libs/utils/ZipEntry.cpp b/tools/aapt/ZipEntry.cpp
index 96f9fc4..bed0333 100644
--- a/libs/utils/ZipEntry.cpp
+++ b/tools/aapt/ZipEntry.cpp
@@ -20,7 +20,7 @@
#define LOG_TAG "zip"
-#include <utils/ZipEntry.h>
+#include "ZipEntry.h"
#include <utils/Log.h>
#include <stdio.h>
diff --git a/include/utils/ZipEntry.h b/tools/aapt/ZipEntry.h
index e4698df..7f721b4 100644
--- a/include/utils/ZipEntry.h
+++ b/tools/aapt/ZipEntry.h
@@ -22,7 +22,7 @@
#ifndef __LIBS_ZIPENTRY_H
#define __LIBS_ZIPENTRY_H
-#include "Errors.h"
+#include <utils/Errors.h>
#include <stdlib.h>
#include <stdio.h>
diff --git a/libs/utils/ZipFile.cpp b/tools/aapt/ZipFile.cpp
index 6f27d17..62c9383 100644
--- a/libs/utils/ZipFile.cpp
+++ b/tools/aapt/ZipFile.cpp
@@ -20,10 +20,11 @@
#define LOG_TAG "zip"
-#include <utils/ZipFile.h>
#include <utils/ZipUtils.h>
#include <utils/Log.h>
+#include "ZipFile.h"
+
#include <zlib.h>
#define DEF_MEM_LEVEL 8 // normally in zutil.h?
@@ -94,10 +95,10 @@ status_t ZipFile::open(const char* zipFileName, int flags)
}
mZipFp = fopen(zipFileName, openflags);
if (mZipFp == NULL) {
- int err = errno;
- LOGD("fopen failed: %d\n", err);
+ int err = errno;
+ LOGD("fopen failed: %d\n", err);
return errnoToStatus(err);
- }
+ }
status_t result;
if (!newArchive) {
@@ -221,8 +222,8 @@ status_t ZipFile::readCentralDir(void)
buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch];
if (buf == NULL) {
- LOGD("Failure allocating %d bytes for EOCD search",
- EndOfCentralDir::kMaxEOCDSearch);
+ LOGD("Failure allocating %d bytes for EOCD search",
+ EndOfCentralDir::kMaxEOCDSearch);
result = NO_MEMORY;
goto bail;
}
@@ -235,7 +236,7 @@ status_t ZipFile::readCentralDir(void)
readAmount = (long) fileLength;
}
if (fseek(mZipFp, seekStart, SEEK_SET) != 0) {
- LOGD("Failure seeking to end of zip at %ld", (long) seekStart);
+ LOGD("Failure seeking to end of zip at %ld", (long) seekStart);
result = UNKNOWN_ERROR;
goto bail;
}
@@ -265,9 +266,9 @@ status_t ZipFile::readCentralDir(void)
/* extract eocd values */
result = mEOCD.readBuf(buf + i, readAmount - i);
if (result != NO_ERROR) {
- LOGD("Failure reading %ld bytes of EOCD values", readAmount - i);
+ LOGD("Failure reading %ld bytes of EOCD values", readAmount - i);
goto bail;
- }
+ }
//mEOCD.dump();
if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 ||
@@ -293,8 +294,8 @@ status_t ZipFile::readCentralDir(void)
* we're hoping to preserve.
*/
if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
- LOGD("Failure seeking to central dir offset %ld\n",
- mEOCD.mCentralDirOffset);
+ LOGD("Failure seeking to central dir offset %ld\n",
+ mEOCD.mCentralDirOffset);
result = UNKNOWN_ERROR;
goto bail;
}
@@ -743,61 +744,61 @@ status_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp,
const void* data, size_t size, unsigned long* pCRC32)
{
status_t result = NO_ERROR;
- const size_t kBufSize = 32768;
- unsigned char* inBuf = NULL;
- unsigned char* outBuf = NULL;
- z_stream zstream;
+ const size_t kBufSize = 32768;
+ unsigned char* inBuf = NULL;
+ unsigned char* outBuf = NULL;
+ z_stream zstream;
bool atEof = false; // no feof() aviailable yet
- unsigned long crc;
- int zerr;
-
- /*
- * Create an input buffer and an output buffer.
- */
- inBuf = new unsigned char[kBufSize];
- outBuf = new unsigned char[kBufSize];
- if (inBuf == NULL || outBuf == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
-
- /*
- * Initialize the zlib stream.
- */
- memset(&zstream, 0, sizeof(zstream));
- zstream.zalloc = Z_NULL;
- zstream.zfree = Z_NULL;
- zstream.opaque = Z_NULL;
- zstream.next_in = NULL;
- zstream.avail_in = 0;
- zstream.next_out = outBuf;
- zstream.avail_out = kBufSize;
- zstream.data_type = Z_UNKNOWN;
-
- zerr = deflateInit2(&zstream, Z_BEST_COMPRESSION,
- Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
- if (zerr != Z_OK) {
- result = UNKNOWN_ERROR;
- if (zerr == Z_VERSION_ERROR) {
- LOGE("Installed zlib is not compatible with linked version (%s)\n",
- ZLIB_VERSION);
- } else {
- LOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr);
- }
- goto bail;
- }
-
- crc = crc32(0L, Z_NULL, 0);
-
- /*
- * Loop while we have data.
- */
- do {
- size_t getSize;
- int flush;
-
- /* only read if the input buffer is empty */
- if (zstream.avail_in == 0 && !atEof) {
+ unsigned long crc;
+ int zerr;
+
+ /*
+ * Create an input buffer and an output buffer.
+ */
+ inBuf = new unsigned char[kBufSize];
+ outBuf = new unsigned char[kBufSize];
+ if (inBuf == NULL || outBuf == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+
+ /*
+ * Initialize the zlib stream.
+ */
+ memset(&zstream, 0, sizeof(zstream));
+ zstream.zalloc = Z_NULL;
+ zstream.zfree = Z_NULL;
+ zstream.opaque = Z_NULL;
+ zstream.next_in = NULL;
+ zstream.avail_in = 0;
+ zstream.next_out = outBuf;
+ zstream.avail_out = kBufSize;
+ zstream.data_type = Z_UNKNOWN;
+
+ zerr = deflateInit2(&zstream, Z_BEST_COMPRESSION,
+ Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+ if (zerr != Z_OK) {
+ result = UNKNOWN_ERROR;
+ if (zerr == Z_VERSION_ERROR) {
+ LOGE("Installed zlib is not compatible with linked version (%s)\n",
+ ZLIB_VERSION);
+ } else {
+ LOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr);
+ }
+ goto bail;
+ }
+
+ crc = crc32(0L, Z_NULL, 0);
+
+ /*
+ * Loop while we have data.
+ */
+ do {
+ size_t getSize;
+ int flush;
+
+ /* only read if the input buffer is empty */
+ if (zstream.avail_in == 0 && !atEof) {
LOGV("+++ reading %d bytes\n", (int)kBufSize);
if (data) {
getSize = size > kBufSize ? kBufSize : size;
@@ -817,54 +818,54 @@ status_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp,
atEof = true;
}
- crc = crc32(crc, inBuf, getSize);
-
- zstream.next_in = inBuf;
- zstream.avail_in = getSize;
- }
-
- if (atEof)
- flush = Z_FINISH; /* tell zlib that we're done */
- else
- flush = Z_NO_FLUSH; /* more to come! */
-
- zerr = deflate(&zstream, flush);
- if (zerr != Z_OK && zerr != Z_STREAM_END) {
- LOGD("zlib deflate call failed (zerr=%d)\n", zerr);
- result = UNKNOWN_ERROR;
- goto z_bail;
- }
-
- /* write when we're full or when we're done */
- if (zstream.avail_out == 0 ||
- (zerr == Z_STREAM_END && zstream.avail_out != (uInt) kBufSize))
- {
- LOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf));
+ crc = crc32(crc, inBuf, getSize);
+
+ zstream.next_in = inBuf;
+ zstream.avail_in = getSize;
+ }
+
+ if (atEof)
+ flush = Z_FINISH; /* tell zlib that we're done */
+ else
+ flush = Z_NO_FLUSH; /* more to come! */
+
+ zerr = deflate(&zstream, flush);
+ if (zerr != Z_OK && zerr != Z_STREAM_END) {
+ LOGD("zlib deflate call failed (zerr=%d)\n", zerr);
+ result = UNKNOWN_ERROR;
+ goto z_bail;
+ }
+
+ /* write when we're full or when we're done */
+ if (zstream.avail_out == 0 ||
+ (zerr == Z_STREAM_END && zstream.avail_out != (uInt) kBufSize))
+ {
+ LOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf));
if (fwrite(outBuf, 1, zstream.next_out - outBuf, dstFp) !=
(size_t)(zstream.next_out - outBuf))
{
- LOGD("write %d failed in deflate\n",
+ LOGD("write %d failed in deflate\n",
(int) (zstream.next_out - outBuf));
- goto z_bail;
- }
+ goto z_bail;
+ }
- zstream.next_out = outBuf;
- zstream.avail_out = kBufSize;
- }
- } while (zerr == Z_OK);
+ zstream.next_out = outBuf;
+ zstream.avail_out = kBufSize;
+ }
+ } while (zerr == Z_OK);
- assert(zerr == Z_STREAM_END); /* other errors should've been caught */
+ assert(zerr == Z_STREAM_END); /* other errors should've been caught */
- *pCRC32 = crc;
+ *pCRC32 = crc;
z_bail:
- deflateEnd(&zstream); /* free up any allocated structures */
+ deflateEnd(&zstream); /* free up any allocated structures */
bail:
- delete[] inBuf;
- delete[] outBuf;
+ delete[] inBuf;
+ delete[] outBuf;
- return result;
+ return result;
}
/*
@@ -1206,7 +1207,7 @@ bail:
/*
* ===========================================================================
- * ZipFile::EndOfCentralDir
+ * ZipFile::EndOfCentralDir
* ===========================================================================
*/
diff --git a/include/utils/ZipFile.h b/tools/aapt/ZipFile.h
index 44df5bb..dbbd072 100644
--- a/include/utils/ZipFile.h
+++ b/tools/aapt/ZipFile.h
@@ -21,11 +21,12 @@
#ifndef __LIBS_ZIPFILE_H
#define __LIBS_ZIPFILE_H
-#include "ZipEntry.h"
-#include "Vector.h"
-#include "Errors.h"
+#include <utils/Vector.h>
+#include <utils/Errors.h>
#include <stdio.h>
+#include "ZipEntry.h"
+
namespace android {
/*
diff --git a/tools/aidl/AST.cpp b/tools/aidl/AST.cpp
index 91802a9..1856cb9 100755
--- a/tools/aidl/AST.cpp
+++ b/tools/aidl/AST.cpp
@@ -841,23 +841,6 @@ Document::Write(FILE* to)
fprintf(to, "package %s;\n", this->package.c_str());
}
- // gather the types for the import statements
- set<Type*> types;
- N = this->classes.size();
- for (i=0; i<N; i++) {
- Class* c = this->classes[i];
- c->GatherTypes(&types);
- }
-
- set<Type*>::iterator it;
- for (it=types.begin(); it!=types.end(); it++) {
- Type* t = *it;
- string pkg = t->Package();
- if (pkg.length() != 0 && pkg != this->package) {
- fprintf(to, "import %s;\n", t->ImportType().c_str());
- }
- }
-
N = this->classes.size();
for (i=0; i<N; i++) {
Class* c = this->classes[i];
diff --git a/tools/aidl/AST.h b/tools/aidl/AST.h
index 1dedd04..aec2164 100755
--- a/tools/aidl/AST.h
+++ b/tools/aidl/AST.h
@@ -5,6 +5,7 @@
#include <vector>
#include <set>
#include <stdarg.h>
+#include <stdio.h>
using namespace std;
diff --git a/tools/aidl/generate_java.cpp b/tools/aidl/generate_java.cpp
index e3c0af0..da20d1f 100644
--- a/tools/aidl/generate_java.cpp
+++ b/tools/aidl/generate_java.cpp
@@ -1,6 +1,7 @@
#include "generate_java.h"
#include "AST.h"
#include "Type.h"
+#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -133,7 +134,7 @@ StubClass::make_as_interface(Type *interfaceType)
Method* m = new Method;
m->comment = "/**\n * Cast an IBinder object into an ";
- m->comment += interfaceType->Name();
+ m->comment += interfaceType->QualifiedName();
m->comment += " interface,\n";
m->comment += " * generating a proxy if needed.\n */";
m->modifiers = PUBLIC | STATIC;
@@ -323,7 +324,7 @@ generate_method(const method_type* method, Class* interface,
transactCodeName += method->name.data;
char transactCodeValue[50];
- sprintf(transactCodeValue, "(IBinder.FIRST_CALL_TRANSACTION + %d)", index);
+ sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
Field* transactCode = new Field(STATIC | FINAL,
new Variable(INT_TYPE, transactCodeName));
@@ -517,7 +518,7 @@ generate_method(const method_type* method, Class* interface,
new LiteralExpression("Stub." + transactCodeName),
_data, _reply ? _reply : NULL_VALUE,
new LiteralExpression(
- oneway ? "IBinder.FLAG_ONEWAY" : "0"));
+ oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
tryStatement->statements->Add(call);
// throw back exceptions.
diff --git a/tools/aidl/options.h b/tools/aidl/options.h
index e9bf0f7..d88d988 100644
--- a/tools/aidl/options.h
+++ b/tools/aidl/options.h
@@ -1,6 +1,7 @@
#ifndef DEVICE_TOOLS_AIDL_H
#define DEVICE_TOOLS_AIDL_H
+#include <string.h>
#include <string>
#include <vector>
diff --git a/tools/localize/Perforce.cpp b/tools/localize/Perforce.cpp
index 3425668..a7f301e 100644
--- a/tools/localize/Perforce.cpp
+++ b/tools/localize/Perforce.cpp
@@ -5,7 +5,10 @@
#include <sstream>
#include <sys/types.h>
#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/wait.h>
+#include <cstdio>
using namespace std;
diff --git a/tools/localize/SourcePos.cpp b/tools/localize/SourcePos.cpp
index 9d7c5c6..dd54f3a 100644
--- a/tools/localize/SourcePos.cpp
+++ b/tools/localize/SourcePos.cpp
@@ -2,6 +2,7 @@
#include <stdarg.h>
#include <set>
+#include <cstdio>
using namespace std;
diff --git a/tools/localize/Values.cpp b/tools/localize/Values.cpp
index e396f8b..8623b97 100644
--- a/tools/localize/Values.cpp
+++ b/tools/localize/Values.cpp
@@ -1,5 +1,6 @@
#include "Values.h"
#include <stdlib.h>
+#include <cstdio>
// =====================================================================================
diff --git a/tools/localize/XLIFFFile.cpp b/tools/localize/XLIFFFile.cpp
index 51f81de..4e217d9 100644
--- a/tools/localize/XLIFFFile.cpp
+++ b/tools/localize/XLIFFFile.cpp
@@ -3,6 +3,7 @@
#include <algorithm>
#include <sys/time.h>
#include <time.h>
+#include <cstdio>
const char* const XLIFF_XMLNS = "urn:oasis:names:tc:xliff:document:1.2";
diff --git a/tools/localize/XMLHandler.h b/tools/localize/XMLHandler.h
index 1130710..324385f 100644
--- a/tools/localize/XMLHandler.h
+++ b/tools/localize/XMLHandler.h
@@ -3,6 +3,7 @@
#include "SourcePos.h"
+#include <algorithm>
#include <string>
#include <vector>
#include <map>
diff --git a/tools/localize/file_utils.cpp b/tools/localize/file_utils.cpp
index 8792b9e..84081f5 100644
--- a/tools/localize/file_utils.cpp
+++ b/tools/localize/file_utils.cpp
@@ -7,6 +7,9 @@
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <cstdio>
#include "log.h"
using namespace android;
diff --git a/tools/localize/file_utils.h b/tools/localize/file_utils.h
index 3b3fa21..7706587 100644
--- a/tools/localize/file_utils.h
+++ b/tools/localize/file_utils.h
@@ -4,6 +4,7 @@
#include "ValuesFile.h"
#include "Configuration.h"
#include <string>
+#include <cstdio>
using namespace std;
diff --git a/tools/localize/localize.cpp b/tools/localize/localize.cpp
index c0d84cc..68c03b6 100644
--- a/tools/localize/localize.cpp
+++ b/tools/localize/localize.cpp
@@ -15,6 +15,7 @@
#include <sstream>
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
using namespace std;
diff --git a/tools/localize/localize_test.cpp b/tools/localize/localize_test.cpp
index 63d904c..931ea95 100644
--- a/tools/localize/localize_test.cpp
+++ b/tools/localize/localize_test.cpp
@@ -1,3 +1,4 @@
+#include <cstdio>
#include "XLIFFFile.h"
#include "ValuesFile.h"
#include "localize.h"
diff --git a/tools/localize/merge_res_and_xliff_test.cpp b/tools/localize/merge_res_and_xliff_test.cpp
index 5a2b0f4..f638a74 100644
--- a/tools/localize/merge_res_and_xliff_test.cpp
+++ b/tools/localize/merge_res_and_xliff_test.cpp
@@ -1,3 +1,4 @@
+#include <cstdio>
#include "merge_res_and_xliff.h"
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 3d65d3c..c31577c 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -58,7 +58,7 @@ interface IWifiManager
int getNumAllowedChannels();
- boolean setNumAllowedChannels(int numChannels);
+ boolean setNumAllowedChannels(int numChannels, boolean persist);
int[] getValidChannelCounts();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 5b8ced6..c4dff6a 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -538,14 +538,15 @@ public class WifiManager {
* for some reason.
* @param numChannels the number of allowed channels. Must be greater than 0
* and less than or equal to 16.
+ * @param persist {@code true} if you want this remembered
* @return {@code true} if the operation succeeds, {@code false} otherwise, e.g.,
* {@code numChannels} is out of range.
*
* @hide pending API council
*/
- public boolean setNumAllowedChannels(int numChannels) {
+ public boolean setNumAllowedChannels(int numChannels, boolean persist) {
try {
- return mService.setNumAllowedChannels(numChannels);
+ return mService.setNumAllowedChannels(numChannels, persist);
} catch (RemoteException e) {
return false;
}
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 2fbc779..e6f4130 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -183,6 +183,10 @@ public class WifiStateTracker extends NetworkStateTracker {
private boolean mUseStaticIp = false;
private int mReconnectCount;
+ // used to store the (non-persisted) num determined during device boot
+ // (from mcc or other phone info) before the driver is started.
+ private int mNumAllowedChannels = 0;
+
// Variables relating to the 'available networks' notification
/**
@@ -571,9 +575,12 @@ public class WifiStateTracker extends NetworkStateTracker {
try {
return setNumAllowedChannels(
Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS));
+ Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS));
} catch (Settings.SettingNotFoundException e) {
- // if setting doesn't exist, stick with the driver default
+ if (mNumAllowedChannels != 0) {
+ WifiNative.setNumAllowedChannelsCommand(mNumAllowedChannels);
+ }
+ // otherwise, use the driver default
}
return true;
}
@@ -587,6 +594,7 @@ public class WifiStateTracker extends NetworkStateTracker {
* {@code numChannels} is outside the valid range.
*/
public synchronized boolean setNumAllowedChannels(int numChannels) {
+ mNumAllowedChannels = numChannels;
return WifiNative.setNumAllowedChannelsCommand(numChannels);
}